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

nickg / nvc / 21458432965

28 Jan 2026 10:49PM UTC coverage: 92.632% (+0.02%) from 92.616%
21458432965

Pull #1384

github

web-flow
Merge a7f274965 into 71ebda0ca
Pull Request #1384: Random signal initialization plugin.

17 of 34 new or added lines in 1 file covered. (50.0%)

1096 existing lines in 29 files now uncovered.

76515 of 82601 relevant lines covered (92.63%)

444886.01 hits per line

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

97.16
/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 "printf.h"
26
#include "tree.h"
27
#include "vcode.h"
28

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

36
DECLARE_AND_DEFINE_ARRAY(vcode_reg);
10,065,308✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_block);
344,130✔
38
DECLARE_AND_DEFINE_ARRAY(vcode_type);
81,282✔
39

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

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

108
DECLARE_AND_DEFINE_ARRAY(op);
11,568,262✔
109

110
typedef struct {
111
   op_array_t ops;
112
   loc_t      last_loc;
113
} block_t;
114

115
typedef struct {
116
   vcode_type_t type;
117
   vcode_type_t stamp;
118
} reg_t;
119

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

146
typedef enum {
147
   VCODE_STAMP_INT,
148
   VCODE_STAMP_REAL,
149
} vstamp_kind_t;
150

151
typedef struct {
152
   vstamp_kind_t kind;
153
   union {
154
      struct {
155
         int64_t low;
156
         int64_t high;
157
      } intg;
158
      struct {
159
         double low;
160
         double high;
161
      } real;
162
   } u;
163
} vstamp_t;
164

165
typedef struct {
166
   vcode_type_t      type;
167
   vcode_type_t      stamp;
168
   ident_t           name;
169
   vcode_var_flags_t flags;
170
} var_t;
171

172
typedef struct {
173
   vcode_type_t  type;
174
   vcode_stamp_t stamp;
175
   ident_t       name;
176
   vcode_reg_t   reg;
177
} param_t;
178

179
DECLARE_AND_DEFINE_ARRAY(param);
31,654✔
180
DECLARE_AND_DEFINE_ARRAY(var);
447,975✔
181
DECLARE_AND_DEFINE_ARRAY(reg);
8,738,094✔
182
DECLARE_AND_DEFINE_ARRAY(block);
137,294✔
183
DECLARE_AND_DEFINE_ARRAY(vtype);
21,763,992✔
184
DECLARE_AND_DEFINE_ARRAY(vstamp);
1,417,281✔
185

186
typedef enum {
187
   UNIT_UNDEFINED     = (1 << 1),
188
} unit_flags_t;
189

190
struct _vcode_unit {
191
   vunit_kind_t   kind;
192
   vcode_unit_t   context;
193
   ident_t        name;
194
   vcode_type_t   result;
195
   block_array_t  blocks;
196
   reg_array_t    regs;
197
   vtype_array_t  types;
198
   vstamp_array_t stamps;
199
   var_array_t    vars;
200
   param_array_t  params;
201
   unsigned       depth;
202
   unit_flags_t   flags;
203
   vcode_unit_t   children;
204
   vcode_unit_t   next;
205
   object_t      *object;
206
};
207

208
#define MASK_CONTEXT(x)   ((x) >> 24)
209
#define MASK_INDEX(x)     ((x) & 0xffffff)
210
#define MAKE_HANDLE(c, i) (((c) & 0xff) << 24 | ((i) & 0xffffff))
211

212
#define VCODE_ASSERT(expr, ...) do                                      \
213
      if (unlikely(!(expr))) {                                          \
214
         vcode_dump_with_mark(vcode_block_data()->ops.count - 1,        \
215
                              NULL, NULL);                              \
216
         fatal_trace(__VA_ARGS__);                                      \
217
      } while (0)
218

219
#define VCODE_FOR_EACH_OP(name)                                 \
220
   block_t *_b = vcode_block_data();                            \
221
   op_t *name; int _i;                                          \
222
   if (_b->ops.count > 0)                                       \
223
      for (_i = _b->ops.count - 1, name = &(_b->ops.items[_i]); \
224
           _i >= 0; name = &(_b->ops.items[--_i]))
225

226
#define VCODE_FOR_EACH_MATCHING_OP(name, k) \
227
   block_t *_b = vcode_block_data();                            \
228
   op_t *name; int _i;                                          \
229
   if (_b->ops.count > 0)                                       \
230
      for (_i = 0, name = &(_b->ops.items[_i]);                 \
231
           _i < _b->ops.count; name = &(_b->ops.items[++_i]))   \
232
         if (name->kind == (k))
233

234
#define VCODE_CHECK_UNIONS 0
235

236
static __thread vcode_unit_t  active_unit  = NULL;
237
static __thread vcode_block_t active_block = VCODE_INVALID_BLOCK;
238

239
static inline int64_t sadd64(int64_t a, int64_t b)
39,320✔
240
{
241
   int64_t result;
39,320✔
242
   if (__builtin_add_overflow(a, b, &result))
39,320✔
243
      return b < 0 ? INT64_MIN : INT64_MAX;
9,923✔
244

245
   return result;
246
}
247

248
static inline int64_t ssub64(int64_t a, int64_t b)
64,632✔
249
{
250
   int64_t result;
64,632✔
251
   if (__builtin_sub_overflow(a, b, &result))
64,632✔
252
      return b > 0 ? INT64_MIN : INT64_MAX;
2,446✔
253

254
   return result;
255
}
256

257
static inline int64_t smul64(int64_t a, int64_t b)
14,712✔
258
{
259
   int64_t result;
14,712✔
260
   if (__builtin_mul_overflow(a, b, &result))
14,712✔
261
      return (a > 0 && b > 0) || (a < 0 && b < 0) ? INT64_MAX : INT64_MIN;
5,028✔
262

263
   return result;
264
}
265

266
static vcode_reg_t vcode_add_reg(vcode_type_t type, vcode_stamp_t stamp)
1,452,501✔
267
{
268
   assert(active_unit != NULL);
1,452,501✔
269

270
   vcode_reg_t reg = active_unit->regs.count;
1,452,501✔
271
   reg_t *r = reg_array_alloc(&(active_unit->regs));
1,452,501✔
272
   memset(r, '\0', sizeof(reg_t));
1,452,501✔
273
   r->type   = type;
1,452,501✔
274
   r->stamp  = stamp;
1,452,501✔
275

276
   return reg;
1,452,501✔
277
}
278

279
static block_t *vcode_block_data(void)
8,354,349✔
280
{
281
   assert(active_unit != NULL);
8,354,349✔
282
   assert(active_block != -1);
8,354,349✔
283
   return &(active_unit->blocks.items[active_block]);
8,354,349✔
284
}
285

286
static op_t *vcode_add_op(vcode_op_t kind)
1,866,322✔
287
{
288
   assert(active_unit != NULL);
1,866,322✔
289
   assert(active_block != VCODE_INVALID_BLOCK);
1,866,322✔
290

291
   VCODE_ASSERT(
1,866,322✔
292
      !vcode_block_finished(),
293
      "attempt to add to already finished block %d", active_block);
294

295
   block_t *block = vcode_block_data();
1,866,322✔
296

297
   op_t *op = op_array_alloc(&(block->ops));
1,866,322✔
298
   memset(op, '\0', sizeof(op_t));
1,866,322✔
299
   op->kind   = kind;
1,866,322✔
300
   op->result = VCODE_INVALID_REG;
1,866,322✔
301
   op->loc    = block->last_loc;
1,866,322✔
302

303
   return op;
1,866,322✔
304
}
305

306
static void vcode_add_arg(op_t *op, vcode_reg_t arg)
3,305,278✔
307
{
308
   vcode_reg_array_add(&(op->args), arg);
3,305,278✔
309
}
3,305,278✔
310

311
static void vcode_add_target(op_t *op, vcode_block_t block)
113,800✔
312
{
313
   vcode_block_array_add(&(op->targets), block);
113,800✔
314
}
113,800✔
315

316
static op_t *vcode_op_data(int op)
9,701,940✔
317
{
318
   assert(active_unit != NULL);
9,701,940✔
319
   assert(active_block != VCODE_INVALID_BLOCK);
9,701,940✔
320

321
   block_t *b = &(active_unit->blocks.items[active_block]);
9,701,940✔
322
   return op_array_nth_ptr(&(b->ops), op);
9,701,940✔
323
}
324

325
static op_t *vcode_find_definition(vcode_reg_t reg)
1,675,799✔
326
{
327
   for (int i = active_block; i >= 0; i--) {
1,706,856✔
328
      block_t *b = &(active_unit->blocks.items[i]);
1,705,592✔
329
      for (int j = b->ops.count - 1; j >= 0; j--) {
33,262,458✔
330
         if (b->ops.items[j].result == reg)
33,231,401✔
331
            return &(b->ops.items[j]);
1,674,535✔
332
      }
333
   }
334

335
   return NULL;
336
}
337

338
#ifdef DEBUG
339
static void vcode_assert_const(vcode_reg_t reg, const char *what)
1,659,407✔
340
{
341
   op_t *defn = vcode_find_definition(reg);
1,659,407✔
342
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
1,659,407✔
343
                what, reg);
344
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
1,659,407✔
345
                || defn->kind == VCODE_OP_CONST_REAL
346
                || defn->kind == VCODE_OP_CONST_RECORD
347
                || defn->kind == VCODE_OP_CONST_ARRAY
348
                || defn->kind == VCODE_OP_CONST_REP
349
                || defn->kind == VCODE_OP_NULL
350
                || defn->kind == VCODE_OP_UNDEFINED,
351
                "constant %s argument r%d is not constant", what, reg);
352
}
1,659,407✔
353
#endif
354

355
static reg_t *vcode_reg_data(vcode_reg_t reg)
7,285,593✔
356
{
357
   assert(active_unit != NULL);
7,285,593✔
358
   assert(reg != VCODE_INVALID_REG);
7,285,593✔
359
   return reg_array_nth_ptr(&(active_unit->regs), reg);
7,285,593✔
360
}
361

362
static vtype_t *vcode_type_data(vcode_type_t type)
5,623,555✔
363
{
364
   assert(type != VCODE_INVALID_TYPE);
5,623,555✔
365
   assert(active_unit != NULL);
5,623,555✔
366
   vcode_unit_t unit = active_unit;
5,623,555✔
367

368
   int depth = MASK_CONTEXT(type);
5,623,555✔
369
   assert(depth <= unit->depth);
5,623,555✔
370
   while (depth != unit->depth)
6,483,363✔
371
      unit = unit->context;
859,808✔
372

373
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
5,623,555✔
374
}
375

376
static vstamp_t *vcode_stamp_data(vcode_stamp_t stamp)
1,158,105✔
377
{
378
   if (stamp == VCODE_INVALID_STAMP)
1,158,105✔
379
      return NULL;
380

381
   assert(active_unit != NULL);
1,080,340✔
382
   vcode_unit_t unit = active_unit;
1,080,340✔
383

384
   int depth = MASK_CONTEXT(stamp);
1,080,340✔
385
   assert(depth <= unit->depth);
1,080,340✔
386
   while (depth != unit->depth)
1,108,456✔
387
      unit = unit->context;
28,116✔
388

389
   return vstamp_array_nth_ptr(&(unit->stamps), MASK_INDEX(stamp));
1,080,340✔
390
}
391

392
static var_t *vcode_var_data(vcode_var_t var)
376,069✔
393
{
394
   assert(active_unit != NULL);
376,069✔
395
   assert(var != VCODE_INVALID_VAR);
376,069✔
396

397
   return var_array_nth_ptr(&(active_unit->vars), var);
376,069✔
398
}
399

400
void vcode_heap_allocate(vcode_reg_t reg)
11,103✔
401
{
402
   op_t *defn = vcode_find_definition(reg);
16,392✔
403
   if (defn == NULL) {
16,392✔
404
      // It is always safe to return a pointer to an argument
405
      return;
406
   }
407

408
   switch (defn->kind) {
15,128✔
409
   case VCODE_OP_CONST:
410
   case VCODE_OP_CONST_REAL:
411
   case VCODE_OP_CONST_ARRAY:
412
   case VCODE_OP_CONST_REP:
413
   case VCODE_OP_NULL:
414
   case VCODE_OP_UNDEFINED:
415
   case VCODE_OP_ADDRESS_OF:
416
   case VCODE_OP_LINK_VAR:
417
   case VCODE_OP_LINK_PACKAGE:
418
   case VCODE_OP_CONTEXT_UPREF:
419
   case VCODE_OP_PACKAGE_INIT:
420
   case VCODE_OP_BIND_EXTERNAL:
421
      break;
422

423
   case VCODE_OP_ALLOC:
424
   case VCODE_OP_REFLECT_SUBTYPE:
425
   case VCODE_OP_REFLECT_VALUE:
426
      // Always allocated in mspace
427
      break;
428

429
   case VCODE_OP_INDEX:
1,258✔
430
      vcode_var_data(defn->address)->flags |= VAR_HEAP;
1,258✔
431
      break;
1,258✔
432

433
   case VCODE_OP_VAR_UPREF:
639✔
434
      {
435
         vcode_unit_t vu = vcode_active_unit();
639✔
436
         for (int i = 0; i < defn->hops; i++)
1,284✔
437
            vu = vcode_unit_context(vu);
645✔
438

439
         vcode_state_t state;
639✔
440
         vcode_state_save(&state);
639✔
441

442
         vcode_select_unit(vu);
639✔
443

444
         vcode_var_data(defn->address)->flags |= VAR_HEAP;
639✔
445

446
         vcode_state_restore(&state);
639✔
447
      }
448
      break;
639✔
449

450
   case VCODE_OP_ARRAY_REF:
469✔
451
      vcode_heap_allocate(defn->args.items[0]);
469✔
452
      break;
469✔
453

454
   case VCODE_OP_WRAP:
4,477✔
455
   case VCODE_OP_UNWRAP:
456
   case VCODE_OP_RESOLVED:
457
      vcode_heap_allocate(defn->args.items[0]);
4,477✔
458
      break;
4,477✔
459

460
   case VCODE_OP_LAST_VALUE:
461
      // Returns a pointer into the C heap
462
      break;
463

464
   case VCODE_OP_LOAD:
1,192✔
465
      {
466
         if (vcode_reg_kind(reg) != VCODE_TYPE_UARRAY)
1,192✔
467
            return;
468

469
         // Any store to this variable must be heap allocated
470
         for (int i = 0; i < active_unit->blocks.count; i++) {
18,539✔
471
            block_t *b = &(active_unit->blocks.items[i]);
17,394✔
472
            for (int j = 0; j < b->ops.count; j++) {
238,822✔
473
               op_t *op = &(b->ops.items[j]);
221,428✔
474
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
221,428✔
475
                  vcode_heap_allocate(op->args.items[0]);
1,145✔
476

477
               VCODE_ASSERT(
221,428✔
478
                  op->kind != VCODE_OP_INDEX || op->address != defn->address,
479
                  "cannot heap allocate aliased pointer r%d", reg);
480
            }
481
         }
482
      }
483
      break;
484

485
   case VCODE_OP_FCALL:
486
      for (int i = 0; i < defn->args.count; i++) {
6,034✔
487
         const vtype_kind_t rkind = vcode_reg_kind(reg);
4,463✔
488
         if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
4,463✔
489
            // Function may return a pointer to its argument
490
            vcode_heap_allocate(defn->args.items[i]);
4,359✔
491
         }
492
      }
493
      break;
494

495
   case VCODE_OP_RECORD_REF:
24✔
496
      vcode_heap_allocate(defn->args.items[0]);
24✔
497
      break;
24✔
498

499
   case VCODE_OP_SELECT:
40✔
500
      vcode_heap_allocate(defn->args.items[1]);
40✔
501
      vcode_heap_allocate(defn->args.items[2]);
40✔
502
      break;
40✔
503

504
   case VCODE_OP_LOAD_INDIRECT:
297✔
505
      {
506
         // Always OK if scalar otherwise check the pointer source
507
         const vtype_kind_t vtkind = vcode_reg_kind(reg);
297✔
508
         if (vtkind != VCODE_TYPE_INT && vtkind != VCODE_TYPE_REAL)
297✔
509
            vcode_heap_allocate(defn->args.items[0]);
279✔
510
      }
511
      break;
512

513
   case VCODE_OP_ALL:
514
      // Must have been allocated on the heap
515
      break;
516

517
   case VCODE_OP_NEW:
518
      // On the heap by definition
519
      break;
520

521
   case VCODE_OP_SUB:
522
   case VCODE_OP_MUL:
523
   case VCODE_OP_DIV:
524
   case VCODE_OP_CAST:
525
   case VCODE_OP_CMP:
526
   case VCODE_OP_OR:
527
   case VCODE_OP_NOT:
528
   case VCODE_OP_AND:
529
   case VCODE_OP_NOR:
530
   case VCODE_OP_NAND:
531
   case VCODE_OP_XOR:
532
   case VCODE_OP_XNOR:
533
   case VCODE_OP_EVENT:
534
   case VCODE_OP_ACTIVE:
535
   case VCODE_OP_UARRAY_LEN:
536
   case VCODE_OP_UARRAY_LEFT:
537
   case VCODE_OP_UARRAY_RIGHT:
538
   case VCODE_OP_UARRAY_DIR:
539
   case VCODE_OP_LAST_EVENT:
540
   case VCODE_OP_NEG:
541
   case VCODE_OP_EXP:
542
   case VCODE_OP_ABS:
543
   case VCODE_OP_MOD:
544
   case VCODE_OP_REM:
545
   case VCODE_OP_ADD:
546
   case VCODE_OP_TRAP_ADD:
547
   case VCODE_OP_TRAP_SUB:
548
   case VCODE_OP_TRAP_MUL:
549
   case VCODE_OP_TRAP_NEG:
550
   case VCODE_OP_TRAP_EXP:
551
      // Result cannot reference pointer
552
      break;
553

554
   default:
UNCOV
555
      VCODE_ASSERT(false, "cannot heap allocate r%d", reg);
×
556
   }
557
}
558

559
void vcode_state_save(vcode_state_t *state)
40,920✔
560
{
561
   state->unit  = active_unit;
40,920✔
562
   state->block = active_block;
40,920✔
563
}
40,920✔
564

565
void vcode_state_restore(const vcode_state_t *state)
40,920✔
566
{
567
   active_unit  = state->unit;
40,920✔
568
   active_block = state->block;
40,920✔
569
}
40,920✔
570

571
void vcode_unit_unref(vcode_unit_t unit)
50,645✔
572
{
573
   assert(unit != NULL);
50,645✔
574

575
   if (unit == active_unit)
50,645✔
576
      vcode_close();
11,178✔
577

578
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
65,835✔
579
      assert(it->context == unit);
15,190✔
580
      it->context = NULL;
15,190✔
581
   }
582
   unit->children = NULL;
50,645✔
583

584
   if (unit->context != NULL) {
50,645✔
585
      vcode_unit_t *it = &(unit->context->children);
12,203✔
586
      for (; *it != NULL && *it != unit; it = &((*it)->next))
35,082✔
587
         ;
588
      assert(*it != NULL);
12,203✔
589
      *it = (*it)->next;
12,203✔
590
   }
591

592
   for (unsigned i = 0; i < unit->blocks.count; i++) {
187,889✔
593
      block_t *b = &(unit->blocks.items[i]);
137,244✔
594

595
      for (unsigned j = 0; j < b->ops.count; j++) {
1,921,860✔
596
         op_t *o = &(b->ops.items[j]);
1,784,616✔
597
         if (OP_HAS_COMMENT(o->kind))
1,784,616✔
598
            free(o->comment);
197,134✔
599
         if (OP_HAS_TARGET(o->kind))
1,784,616✔
600
            free(o->targets.items);
80,880✔
601
         free(o->args.items);
1,784,616✔
602
      }
603
      free(b->ops.items);
137,244✔
604
   }
605
   free(unit->blocks.items);
50,645✔
606

607
   for (unsigned i = 0; i < unit->types.count; i++) {
380,338✔
608
      vtype_t *vt = &(unit->types.items[i]);
329,693✔
609
      if (vt->kind == VCODE_TYPE_RECORD)
329,693✔
610
         free(vt->fields.items);
5,808✔
611
   }
612
   free(unit->types.items);
50,645✔
613

614
   free(unit->stamps.items);
50,645✔
615
   free(unit->regs.items);
50,645✔
616
   free(unit->vars.items);
50,645✔
617
   free(unit->params.items);
50,645✔
618
   free(unit);
50,645✔
619
}
50,645✔
620

621
vcode_unit_t vcode_unit_next(vcode_unit_t unit)
6,991✔
622
{
623
   return unit->next;
6,991✔
624
}
625

626
vcode_unit_t vcode_unit_child(vcode_unit_t unit)
10,729✔
627
{
628
   return unit->children;
10,729✔
629
}
630

631
int vcode_count_regs(void)
50,607✔
632
{
633
   assert(active_unit != NULL);
50,607✔
634
   return active_unit->regs.count;
50,607✔
635
}
636

637
vcode_type_t vcode_reg_type(vcode_reg_t reg)
5,478,057✔
638
{
639
   return vcode_reg_data(reg)->type;
5,478,057✔
640
}
641

642
vtype_kind_t vcode_reg_kind(vcode_reg_t reg)
1,343,128✔
643
{
644
   return vtype_kind(vcode_reg_type(reg));
1,343,128✔
645
}
646

647
vcode_stamp_t vcode_reg_stamp(vcode_reg_t reg)
226,127✔
648
{
649
   return vcode_reg_data(reg)->stamp;
226,127✔
650
}
651

652
bool vcode_reg_const(vcode_reg_t reg, int64_t *value)
872,513✔
653
{
654
   reg_t *r = vcode_reg_data(reg);
872,513✔
655

656
   if (r->stamp == VCODE_INVALID_STAMP)
872,513✔
657
      return false;
658

659
   const vstamp_t *s = vcode_stamp_data(r->stamp);
658,069✔
660

661
   if (s->kind != VCODE_STAMP_INT)
658,069✔
662
      return false;
663

664
   if (s->u.intg.low == s->u.intg.high) {
631,881✔
665
      if (value) *value = s->u.intg.low;
473,668✔
666
      return true;
473,668✔
667
   }
668
   else
669
      return false;
670
}
671

672
bool vcode_reg_bounds(vcode_reg_t reg, int64_t *low, int64_t *high)
388,816✔
673
{
674
   reg_t *r = vcode_reg_data(reg);
388,816✔
675
   if (r->stamp == VCODE_INVALID_STAMP) {
388,816✔
676
      vtype_t *t = vcode_type_data(r->type);
74,964✔
677
      if (t->kind == VCODE_TYPE_INT || t->kind == VCODE_TYPE_OFFSET) {
74,964✔
678
         *low = t->low;
73,900✔
679
         *high = t->high;
73,900✔
680
         return true;
73,900✔
681
      }
682
   }
683
   else {
684
      vstamp_t *s = vcode_stamp_data(r->stamp);
313,852✔
685
      if (s->kind == VCODE_STAMP_INT) {
313,852✔
686
         *low = s->u.intg.low;
313,424✔
687
         *high = s->u.intg.high;
313,424✔
688
         return true;
313,424✔
689
      }
690
   }
691

692
   return false;
693
}
694

695
bool vcode_reg_bounds_real(vcode_reg_t reg, double *low, double *high)
1,112✔
696
{
697
   reg_t *r = vcode_reg_data(reg);
1,112✔
698
   if (r->stamp == VCODE_INVALID_STAMP) {
1,112✔
699
      vtype_t *t = vcode_type_data(r->type);
659✔
700
      if (t->kind == VCODE_TYPE_REAL) {
659✔
701
         *low = t->rlow;
659✔
702
         *high = t->rhigh;
659✔
703
         return true;
659✔
704
      }
705
   }
706
   else {
707
      vstamp_t *s = vcode_stamp_data(r->stamp);
453✔
708
      if (s->kind == VCODE_STAMP_REAL) {
453✔
709
         *low = s->u.real.low;
453✔
710
         *high = s->u.real.high;
453✔
711
         return true;
453✔
712
      }
713
   }
714

715
   return false;
716
}
717

718
void vcode_opt(void)
50,671✔
719
{
720
   // Prune assignments to unused registers
721

722
   int *uses LOCAL = xmalloc_array(active_unit->regs.count, sizeof(int));
101,342✔
723

724
   int pruned = 0;
50,671✔
725
   do {
72,781✔
726
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
72,781✔
727
      pruned = 0;
72,781✔
728

729
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
300,239✔
730
         block_t *b = &(active_unit->blocks.items[i]);
227,458✔
731

732
         for (int j = b->ops.count - 1; j >= 0; j--) {
3,539,349✔
733
            op_t *o = &(b->ops.items[j]);
3,311,891✔
734

735
            switch (o->kind) {
3,311,891✔
736
            case VCODE_OP_FCALL:
54,994✔
737
               if (o->result == VCODE_INVALID_REG)
54,994✔
738
                  break;
739
            case VCODE_OP_CONST:
740
            case VCODE_OP_CONST_REAL:
741
            case VCODE_OP_CONST_ARRAY:
742
            case VCODE_OP_CONST_RECORD:
743
            case VCODE_OP_CONST_REP:
744
            case VCODE_OP_LOAD:
745
            case VCODE_OP_LOAD_INDIRECT:
746
            case VCODE_OP_VAR_UPREF:
747
            case VCODE_OP_ADD:
748
            case VCODE_OP_ARRAY_REF:
749
            case VCODE_OP_SUB:
750
            case VCODE_OP_MUL:
751
            case VCODE_OP_CMP:
752
            case VCODE_OP_INDEX:
753
            case VCODE_OP_WRAP:
754
            case VCODE_OP_EXP:
755
            case VCODE_OP_UNDEFINED:
756
            case VCODE_OP_UARRAY_LEN:
757
            case VCODE_OP_UARRAY_DIR:
758
            case VCODE_OP_UARRAY_LEFT:
759
            case VCODE_OP_UARRAY_RIGHT:
760
            case VCODE_OP_UNWRAP:
761
            case VCODE_OP_NULL:
762
            case VCODE_OP_ADDRESS_OF:
763
            case VCODE_OP_RANGE_NULL:
764
            case VCODE_OP_RANGE_LENGTH:
765
            case VCODE_OP_DEBUG_LOCUS:
766
            case VCODE_OP_SELECT:
767
            case VCODE_OP_CAST:
768
            case VCODE_OP_RESOLVED:
769
            case VCODE_OP_TRAP_ADD:
770
            case VCODE_OP_TRAP_SUB:
771
            case VCODE_OP_TRAP_MUL:
772
            case VCODE_OP_TRAP_EXP:
773
            case VCODE_OP_ALLOC:
774
            case VCODE_OP_FUNCTION_TRIGGER:
775
            case VCODE_OP_CMP_TRIGGER:
776
            case VCODE_OP_OR_TRIGGER:
777
               if (uses[o->result] == -1) {
2,110,379✔
UNCOV
778
                  vcode_dump_with_mark(j, NULL, NULL);
×
779
                  fatal_trace("definition of r%d does not dominate all uses",
780
                              o->result);
781
               }
782
               else if (uses[o->result] == 0) {
2,110,379✔
783
                  if (false DEBUG_ONLY(|| o->kind != VCODE_OP_CONST)) {
199,826✔
784
                     o->comment = xasprintf("Dead %s definition of r%d",
118,905✔
785
                                            vcode_op_string(o->kind),
786
                                            o->result);
787
                     o->kind = VCODE_OP_COMMENT;
118,905✔
788
                  }
789
                  else
790
                     o->kind = (vcode_op_t)-1;
80,921✔
791
                  vcode_reg_array_resize(&(o->args), 0, VCODE_INVALID_REG);
199,826✔
792
                  pruned++;
199,826✔
793
               }
794
               uses[o->result] = -1;
2,110,379✔
795
               break;
2,110,379✔
796

797
            default:
798
               break;
799
            }
800

801
            for (int k = 0; k < o->args.count; k++) {
9,359,582✔
802
               if (o->args.items[k] != VCODE_INVALID_REG)
6,047,691✔
803
                  uses[o->args.items[k]]++;
6,012,113✔
804
            }
805
         }
806
      }
807
   } while (pruned > 0);
72,781✔
808

809
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
187,965✔
810
      block_t *b = &(active_unit->blocks.items[i]);
137,294✔
811
      op_t *dst = &(b->ops.items[0]);
137,294✔
812
      size_t copied = 0;
137,294✔
813
      for (int j = 0; j < b->ops.count; j++) {
2,003,616✔
814
         const op_t *src = &(b->ops.items[j]);
1,866,322✔
815
         if (src->kind != (vcode_op_t)-1) {
1,866,322✔
816
            if (src != dst) {
1,785,401✔
817
               assert(dst < src);
584,625✔
818
               *dst = *src;
584,625✔
819
            }
820
            dst++;
1,785,401✔
821
            copied++;
1,785,401✔
822
         }
823
      }
824

825
      assert(copied <= b->ops.count);
137,294✔
826
      b->ops.count = copied;
137,294✔
827
   }
828
}
50,671✔
829

830
void vcode_close(void)
30,892✔
831
{
832
   active_unit  = NULL;
30,892✔
833
   active_block = -1;
30,892✔
834
}
30,892✔
835

836
int vcode_count_blocks(void)
61,602✔
837
{
838
   assert(active_unit != NULL);
61,602✔
839
   return active_unit->blocks.count;
61,602✔
840
}
841

842
int vcode_count_ops(void)
153,711✔
843
{
844
   assert(active_unit != NULL);
153,711✔
845
   assert(active_block != VCODE_INVALID_BLOCK);
153,711✔
846
   return active_unit->blocks.items[active_block].ops.count;
153,711✔
847
}
848

849
int vcode_count_vars(void)
50,619✔
850
{
851
   assert(active_unit != NULL);
50,619✔
852
   return active_unit->vars.count;
50,619✔
853
}
854

855
vcode_var_t vcode_find_var(ident_t name)
15✔
856
{
857
   assert(active_unit != NULL);
15✔
858
   for (int i = 0; i < active_unit->vars.count; i++) {
27✔
859
      if (active_unit->vars.items[i].name == name)
12✔
UNCOV
860
         return i;
×
861
   }
862

863
   return VCODE_INVALID_VAR;
864
}
865

866
ident_t vcode_var_name(vcode_var_t var)
76,328✔
867
{
868
   return vcode_var_data(var)->name;
76,328✔
869
}
870

871
vcode_type_t vcode_var_type(vcode_var_t var)
77,052✔
872
{
873
   return vcode_var_data(var)->type;
77,052✔
874
}
875

876
vcode_var_flags_t vcode_var_flags(vcode_var_t var)
78,414✔
877
{
878
   return vcode_var_data(var)->flags;
78,414✔
879
}
880

881
vcode_op_t vcode_get_op(int op)
2,082,832✔
882
{
883
   return vcode_op_data(op)->kind;
2,082,832✔
884
}
885

886
ident_t vcode_get_func(int op)
75,406✔
887
{
888
   op_t *o = vcode_op_data(op);
75,406✔
889
   assert(OP_HAS_FUNC(o->kind));
75,406✔
890
   return o->func;
75,406✔
891
}
892

893
ident_t vcode_get_ident(int op)
12,845✔
894
{
895
   op_t *o = vcode_op_data(op);
12,845✔
896
   assert(OP_HAS_IDENT(o->kind));
12,845✔
897
   return o->ident;
12,845✔
898
}
899

900
object_t *vcode_get_object(int op)
77,875✔
901
{
902
   op_t *o = vcode_op_data(op);
77,875✔
903
   assert(OP_HAS_IDENT(o->kind));
77,875✔
904
   return o->object;
77,875✔
905
}
906

907
int64_t vcode_get_value(int op)
368,035✔
908
{
909
   op_t *o = vcode_op_data(op);
368,035✔
910
   assert(OP_HAS_VALUE(o->kind));
368,035✔
911
   return o->value;
368,035✔
912
}
913

914
double vcode_get_real(int op)
22,260✔
915
{
916
   op_t *o = vcode_op_data(op);
22,260✔
917
   assert(OP_HAS_REAL(o->kind));
22,260✔
918
   return o->real;
22,260✔
919
}
920

921
vcode_var_t vcode_get_address(int op)
184,975✔
922
{
923
   op_t *o = vcode_op_data(op);
184,975✔
924
   assert(OP_HAS_ADDRESS(o->kind));
184,975✔
925
   return o->address;
184,975✔
926
}
927

928
unsigned vcode_get_dim(int op)
64,352✔
929
{
930
   op_t *o = vcode_op_data(op);
64,352✔
931
   assert(OP_HAS_DIM(o->kind));
64,352✔
932
   return o->dim;
64,352✔
933
}
934

935
int vcode_get_hops(int op)
55,059✔
936
{
937
   op_t *o = vcode_op_data(op);
55,059✔
938
   assert(OP_HAS_HOPS(o->kind));
55,059✔
939
   return o->hops;
55,059✔
940
}
941

942
int vcode_get_field(int op)
33,288✔
943
{
944
   op_t *o = vcode_op_data(op);
33,288✔
945
   assert(OP_HAS_FIELD(o->kind));
33,288✔
946
   return o->field;
33,288✔
947
}
948

949
vcode_var_t vcode_get_type(int op)
63,263✔
950
{
951
   op_t *o = vcode_op_data(op);
63,263✔
952
   assert(OP_HAS_TYPE(o->kind));
63,263✔
953
   return o->type;
63,263✔
954
}
955

956
int vcode_count_args(int op)
245,539✔
957
{
958
   return vcode_op_data(op)->args.count;
245,539✔
959
}
960

961
vcode_reg_t vcode_get_arg(int op, int arg)
3,254,636✔
962
{
963
   op_t *o = vcode_op_data(op);
3,254,636✔
964
   return vcode_reg_array_nth(&(o->args), arg);
3,254,636✔
965
}
966

967
vcode_reg_t vcode_get_result(int op)
1,225,741✔
968
{
969
   op_t *o = vcode_op_data(op);
1,225,741✔
970
   return o->result;
1,225,741✔
971
}
972

973
vcode_cmp_t vcode_get_cmp(int op)
33,646✔
974
{
975
   op_t *o = vcode_op_data(op);
33,646✔
976
   assert(OP_HAS_CMP(o->kind));
33,646✔
977
   return o->cmp;
33,646✔
978
}
979

980
uint32_t vcode_get_tag(int op)
2,909✔
981
{
982
   op_t *o = vcode_op_data(op);
2,909✔
983
   assert(OP_HAS_TAG(o->kind));
2,909✔
984
   return o->tag;
2,909✔
985
}
986

987
const loc_t *vcode_get_loc(int op)
1,784,443✔
988
{
989
   op_t *o = vcode_op_data(op);
1,784,443✔
990
   return &(o->loc);
1,784,443✔
991
}
992

993
vcode_block_t vcode_get_target(int op, int nth)
114,836✔
994
{
995
   op_t *o = vcode_op_data(op);
114,836✔
996
   assert(OP_HAS_TARGET(o->kind));
114,836✔
997
   return vcode_block_array_nth(&(o->targets), nth);
114,836✔
998
}
999

UNCOV
1000
bool vcode_block_empty(void)
×
1001
{
1002
   assert(active_unit != NULL);
×
UNCOV
1003
   assert(active_block != VCODE_INVALID_BLOCK);
×
1004

UNCOV
1005
   return active_unit->blocks.items[active_block].ops.count == 0;
×
1006
}
1007

1008
bool vcode_block_finished(void)
1,982,675✔
1009
{
1010
   assert(active_unit != NULL);
1,982,675✔
1011
   assert(active_block != VCODE_INVALID_BLOCK);
1,982,675✔
1012

1013
   const block_t *b = &(active_unit->blocks.items[active_block]);
1,982,675✔
1014
   if (b->ops.count == 0)
1,982,675✔
1015
      return false;
1016
   else {
1017
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,797,178✔
1018
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,797,178✔
1019
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,797,160✔
1020
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
1021
         || kind == VCODE_OP_UNREACHABLE;
3,594,338✔
1022
   }
1023
}
1024

1025
const char *vcode_op_string(vcode_op_t op)
118,905✔
1026
{
1027
   static const char *strs[] = {
118,905✔
1028
      "cmp", "fcall", "wait", "const", "assert", "jump", "load", "store",
1029
      "mul", "add", "comment", "const array", "index", "sub", "cast",
1030
      "load indirect", "store indirect", "return", "sched waveform",
1031
      "cond", "report", "div", "neg", "exp", "abs", "mod", "rem", "alloc",
1032
      "select", "or", "wrap", "uarray left", "uarray right", "uarray dir",
1033
      "unwrap", "not", "and", "event", "active", "const record", "record ref",
1034
      "copy", "sched event", "pcall", "resume", "xor", "xnor", "nand", "nor",
1035
      "memset", "case", "file open", "file write",
1036
      "file read", "null", "new", "null check", "deallocate", "all",
1037
      "const real", "last event", "debug out", "cover stmt", "cover branch",
1038
      "cover toggle", "cover expr", "cover state", "uarray len", "undefined",
1039
      "range null", "var upref", "resolved", "last value", "init signal",
1040
      "map signal", "drive signal", "link var", "resolution wrapper",
1041
      "last active", "driving", "driving value", "address of", "closure",
1042
      "protected init", "context upref", "const rep", "protected free",
1043
      "implicit signal", "disconnect", "link package",
1044
      "index check", "debug locus", "length check", "range check", "array ref",
1045
      "range length", "exponent check", "zero check", "map const",
1046
      "resolve signal", "package scope", "pop scope", "alias signal",
1047
      "trap add", "trap sub", "trap mul", "force", "release",
1048
      "unreachable", "package init", "trap neg", "process init", "clear event",
1049
      "trap exp", "enter state", "reflect value", "reflect subtype",
1050
      "function trigger", "add trigger", "transfer signal",
1051
      "port conversion", "convert in", "convert out", "bind foreign",
1052
      "or trigger", "cmp trigger", "instance name",
1053
      "map implicit", "bind external", "array scope", "record scope",
1054
      "put conversion", "dir check", "sched process", "table ref",
1055
      "get counters",
1056
   };
1057
   if ((unsigned)op >= ARRAY_LEN(strs))
118,905✔
1058
      return "???";
1059
   else
1060
      return strs[op];
118,905✔
1061
}
1062

1063
LCOV_EXCL_START
1064
static int vcode_dump_reg(vcode_reg_t reg)
1065
{
1066
   if (reg == VCODE_INVALID_REG)
1067
      return nvc_printf("$red$invalid$$");
1068
   else
1069
      return nvc_printf("$green$r%d$$", reg);
1070
}
1071

1072
static int vcode_pretty_print_int(int64_t n)
1073
{
1074
   if (n == INT64_MAX)
1075
      return printf("2^63-1");
1076
   else if (n == INT64_MIN)
1077
      return printf("-2^63");
1078
   else if (n == INT32_MAX)
1079
      return printf("2^31-1");
1080
   else if (n == INT32_MIN)
1081
      return printf("-2^31");
1082
   else
1083
      return printf("%"PRIi64, n);
1084
}
1085

1086
static int vcode_dump_one_type(vcode_type_t type)
1087
{
1088
   int col = 0;
1089
   vtype_t *vt = vcode_type_data(type);
1090
   switch (vt->kind) {
1091
   case VCODE_TYPE_INT:
1092
      if (vt->low != vt->high) {
1093
         col += vcode_pretty_print_int(vt->low);
1094
         col += printf("..");
1095
         col += vcode_pretty_print_int(vt->high);
1096
      }
1097
      else
1098
         col += vcode_pretty_print_int(vt->low);
1099
      break;
1100

1101
   case VCODE_TYPE_REAL:
1102
      if (vt->rlow == -DBL_MAX && vt->rhigh == DBL_MAX)
1103
         col += printf("%%");
1104
      else if (vt->rlow == vt->rhigh)
1105
         col += printf("%f", vt->rlow);
1106
      else
1107
         col += printf("%f..%f", vt->rlow, vt->rhigh);
1108
      break;
1109

1110
   case VCODE_TYPE_CARRAY:
1111
      {
1112
         col += printf("[%u] : ", vt->size);
1113
         col += vcode_dump_one_type(vt->elem);
1114
      }
1115
      break;
1116

1117
   case VCODE_TYPE_UARRAY:
1118
      {
1119
         col += printf("[");
1120
         for (unsigned i = 0; i < vt->dims; i++)
1121
            col += printf("%s*", i > 0 ? ", " : "");
1122
         col += printf("] : ");
1123
         col += vcode_dump_one_type(vt->elem);
1124
      }
1125
      break;
1126

1127
   case VCODE_TYPE_POINTER:
1128
      col += printf("@<");
1129
      col += vcode_dump_one_type(vt->pointed);
1130
      col += printf(">");
1131
      break;
1132

1133
   case VCODE_TYPE_ACCESS:
1134
      col += printf("A<");
1135
      col += vcode_dump_one_type(vt->pointed);
1136
      col += printf(">");
1137
      break;
1138

1139
   case VCODE_TYPE_SIGNAL:
1140
      col += printf("$<");
1141
      col += vcode_dump_one_type(vt->base);
1142
      col += printf(">");
1143
      break;
1144

1145
   case VCODE_TYPE_OFFSET:
1146
      col += printf("#");
1147
      break;
1148

1149
   case VCODE_TYPE_RECORD:
1150
      col += printf("%s{}", istr(vt->name));
1151
      break;
1152

1153
   case VCODE_TYPE_FILE:
1154
      col += printf("F<");
1155
      col += vcode_dump_one_type(vt->base);
1156
      col += printf(">");
1157
      break;
1158

1159
   case VCODE_TYPE_OPAQUE:
1160
      col += printf("?");
1161
      break;
1162

1163
   case VCODE_TYPE_RESOLUTION:
1164
      col += printf("R<");
1165
      col += vcode_dump_one_type(vt->base);
1166
      col += printf(">");
1167
      break;
1168

1169
   case VCODE_TYPE_CLOSURE:
1170
      col += printf("C<");
1171
      col += vcode_dump_one_type(vt->base);
1172
      col += printf(">");
1173
      break;
1174

1175
   case VCODE_TYPE_CONTEXT:
1176
      col += printf("P<%s>", istr(vt->name));
1177
      break;
1178

1179
   case VCODE_TYPE_DEBUG_LOCUS:
1180
      col += printf("D<>");
1181
      break;
1182

1183
   case VCODE_TYPE_TRIGGER:
1184
      col += printf("T<>");
1185
      break;
1186

1187
   case VCODE_TYPE_CONVERSION:
1188
      col += printf("X<>");
1189
      break;
1190
   }
1191

1192
   return col;
1193
}
1194

1195
static void vcode_dump_tab(int col, int to_col)
1196
{
1197
   if (col >= to_col)
1198
      printf(" ");
1199
   else {
1200
      while (col < to_col)
1201
         col += printf(" ");
1202
   }
1203
}
1204

1205
static void vcode_dump_comment(int col)
1206
{
1207
   vcode_dump_tab(col, 40);
1208
   nvc_printf("$cyan$// ");
1209
}
1210

1211
static void vcode_dump_type(int col, vcode_type_t type, vcode_stamp_t stamp)
1212
{
1213
   vcode_dump_comment(col);
1214
   vcode_dump_one_type(type);
1215

1216
   if (stamp == VCODE_INVALID_STAMP)
1217
      return;
1218

1219
   printf(" => ");
1220

1221
   const vstamp_t *s = vcode_stamp_data(stamp);
1222
   switch (s->kind) {
1223
   case VCODE_STAMP_INT:
1224
      if (s->u.intg.low != s->u.intg.high) {
1225
         vcode_pretty_print_int(s->u.intg.low);
1226
         printf("..");
1227
         vcode_pretty_print_int(s->u.intg.high);
1228
      }
1229
      else
1230
         vcode_pretty_print_int(s->u.intg.low);
1231
      break;
1232

1233
   case VCODE_STAMP_REAL:
1234
      if (s->u.real.low != s->u.real.high)
1235
         printf("%g..%g", s->u.real.low, s->u.real.high);
1236
      else
1237
         printf("%g", s->u.real.low);
1238
      break;
1239

1240
   default:
1241
      should_not_reach_here();
1242
   }
1243
}
1244

1245
static void vcode_dump_result_type(int col, const op_t *op)
1246
{
1247
   if (op->result != VCODE_INVALID_REG) {
1248
      reg_t *r = vcode_reg_data(op->result);
1249
      vcode_dump_type(col, r->type, r->stamp);
1250
   }
1251
}
1252

1253
static int vcode_dump_var(vcode_var_t var, int hops)
1254
{
1255
   vcode_unit_t owner = active_unit;
1256
   while (owner && hops--)
1257
      owner = owner->context;
1258

1259
   if (owner == NULL || var >= owner->vars.count)
1260
      return nvc_printf("$red$invalid$$");
1261
   else {
1262
      var_t *v = var_array_nth_ptr(&(owner->vars), var);
1263
      return nvc_printf("$magenta$%s$$", istr(v->name));
1264
   }
1265
}
1266

1267
void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg)
1268
{
1269
   assert(active_unit != NULL);
1270

1271
   const vcode_unit_t vu = active_unit;
1272
   vcode_block_t old_block = active_block;
1273

1274
   printf("\n");
1275
   if (vu->name != NULL)
1276
      nvc_printf("Name       $cyan$%s$$\n", istr(vu->name));
1277
   nvc_printf("Kind       $cyan$");
1278
   switch (vu->kind) {
1279
   case VCODE_UNIT_PROCESS:   printf("process"); break;
1280
   case VCODE_UNIT_FUNCTION:  printf("function"); break;
1281
   case VCODE_UNIT_PROCEDURE: printf("procedure"); break;
1282
   case VCODE_UNIT_INSTANCE:  printf("instance"); break;
1283
   case VCODE_UNIT_THUNK:     printf("thunk"); break;
1284
   case VCODE_UNIT_PACKAGE:   printf("package"); break;
1285
   case VCODE_UNIT_PROTECTED: printf("protected"); break;
1286
   case VCODE_UNIT_PROPERTY:  printf("property"); break;
1287
   }
1288
   nvc_printf("$$\n");
1289
   if (vu->context != NULL)
1290
      nvc_printf("Context    $cyan$%s$$\n", istr(vu->context->name));
1291
   printf("Blocks     %d\n", vu->blocks.count);
1292
   printf("Registers  %d\n", vu->regs.count);
1293
   printf("Types      %d\n", vu->types.count);
1294
   printf("Stamps     %d\n", vu->stamps.count);
1295

1296
   for (int i = 0; i < vu->types.count; i++) {
1297
      const vtype_t *t = &(vu->types.items[i]);
1298
      if (t->kind == VCODE_TYPE_RECORD) {
1299
         int col = 0;
1300
         col += nvc_printf("  $magenta$%s$$", istr(t->name));
1301
         vcode_dump_tab(col, 40);
1302
         nvc_printf("$cyan${");
1303
         for (unsigned i = 0; i < t->fields.count; i++) {
1304
            if (i > 0)
1305
               printf(", ");
1306
            vcode_dump_one_type(t->fields.items[i]);
1307
         }
1308
         nvc_printf("}$$\n");
1309
      }
1310
   }
1311

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

1314
   for (int i = 0; i < vu->vars.count; i++) {
1315
      const var_t *v = &(vu->vars.items[i]);
1316
      int col = printf("  ");
1317
      col += nvc_printf("$magenta$%s$$", istr(v->name));
1318
      vcode_dump_type(col, v->type, v->stamp);
1319
      if (v->flags & VAR_SIGNAL)
1320
         col += printf(", signal");
1321
      if (v->flags & VAR_HEAP)
1322
         col += printf(", heap");
1323
      if (v->flags & VAR_CONST)
1324
         col += printf(", constant");
1325
      if (v->flags & VAR_TEMP)
1326
         col += printf(", temp");
1327
      nvc_printf("$$\n");
1328
   }
1329

1330
   if (vu->result != VCODE_INVALID_TYPE) {
1331
      nvc_printf("Result     $cyan$");
1332
      vcode_dump_one_type(vu->result);
1333
      nvc_printf("$$\n");
1334
   }
1335

1336
   if (vu->kind == VCODE_UNIT_FUNCTION
1337
       || vu->kind == VCODE_UNIT_PROCEDURE
1338
       || vu->kind == VCODE_UNIT_PROPERTY
1339
       || (vu->kind == VCODE_UNIT_PROTECTED && vu->params.count > 0)) {
1340

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

1343
      for (size_t i = 0; i < vu->params.count; i++) {
1344
         const param_t *p = &(vu->params.items[i]);
1345
         int col = printf("  ");
1346
         col += vcode_dump_reg(p->reg);
1347
         while (col < 8)
1348
            col += printf(" ");
1349
         col += nvc_printf("$magenta$%s$$", istr(p->name));
1350
         vcode_dump_type(col, p->type, p->stamp);
1351
         nvc_printf("$$\n");
1352
      }
1353
   }
1354

1355
   printf("Begin\n");
1356
   for (int i = 0; i < vu->blocks.count; i++) {
1357
      active_block = i;
1358
      const block_t *b = &(vu->blocks.items[i]);
1359
      for (int j = 0; j < b->ops.count; j++) {
1360
         int col = 0;
1361
         if (j == 0)
1362
            col += nvc_printf("  $yellow$%2d:$$ ", i);
1363
         else
1364
            col += printf("      ");
1365

1366
         const op_t *op = &(b->ops.items[j]);
1367
         switch (op->kind) {
1368
         case VCODE_OP_CMP:
1369
            {
1370
               vcode_dump_reg(op->result);
1371
               printf(" := %s ", vcode_op_string(op->kind));
1372
               vcode_dump_reg(op->args.items[0]);
1373
               switch (op->cmp) {
1374
               case VCODE_CMP_EQ:  printf(" == "); break;
1375
               case VCODE_CMP_NEQ: printf(" != "); break;
1376
               case VCODE_CMP_LT:  printf(" < "); break;
1377
               case VCODE_CMP_GT:  printf(" > "); break;
1378
               case VCODE_CMP_LEQ: printf(" <= "); break;
1379
               case VCODE_CMP_GEQ: printf(" >= "); break;
1380
               }
1381
               vcode_dump_reg(op->args.items[1]);
1382
            }
1383
            break;
1384

1385
         case VCODE_OP_CONST:
1386
            {
1387
               col += vcode_dump_reg(op->result);
1388
               col += printf(" := %s %"PRIi64"",
1389
                             vcode_op_string(op->kind),
1390
                             op->value);
1391
               vcode_dump_result_type(col, op);
1392
            }
1393
            break;
1394

1395
         case VCODE_OP_CONST_REAL:
1396
            {
1397
               col += vcode_dump_reg(op->result);
1398
               col += printf(" := %s %g",
1399
                             vcode_op_string(op->kind),
1400
                             op->real);
1401
               vcode_dump_result_type(col, op);
1402
            }
1403
            break;
1404

1405
         case VCODE_OP_ALLOC:
1406
            {
1407
               col += vcode_dump_reg(op->result);
1408
               col += printf(" := %s ", vcode_op_string(op->kind));
1409
               col += vcode_dump_reg(op->args.items[0]);
1410
               vcode_dump_result_type(col, op);
1411
            }
1412
            break;
1413

1414
         case VCODE_OP_FCALL:
1415
            {
1416
               if (op->result != VCODE_INVALID_REG) {
1417
                  col += vcode_dump_reg(op->result);
1418
                  col += printf(" := ");
1419
               }
1420
               col += nvc_printf("%s $magenta$%s$$ ",
1421
                                 vcode_op_string(op->kind),
1422
                                 istr(op->func));
1423
               for (int i = 0; i < op->args.count; i++) {
1424
                  if (i > 0)
1425
                     col += printf(", ");
1426
                  col += vcode_dump_reg(op->args.items[i]);
1427
               }
1428
               vcode_dump_result_type(col, op);
1429
            }
1430
            break;
1431

1432
         case VCODE_OP_MAP_CONST:
1433
         case VCODE_OP_MAP_SIGNAL:
1434
         case VCODE_OP_MAP_IMPLICIT:
1435
            {
1436
               printf("%s ", vcode_op_string(op->kind));
1437
               vcode_dump_reg(op->args.items[0]);
1438
               printf(" to ");
1439
               vcode_dump_reg(op->args.items[1]);
1440
               printf(" count ");
1441
               vcode_dump_reg(op->args.items[2]);
1442
            }
1443
            break;
1444

1445
         case VCODE_OP_DRIVE_SIGNAL:
1446
            {
1447
               printf("%s ", vcode_op_string(op->kind));
1448
               vcode_dump_reg(op->args.items[0]);
1449
               printf(" count ");
1450
               vcode_dump_reg(op->args.items[1]);
1451
            }
1452
            break;
1453

1454
         case VCODE_OP_TRANSFER_SIGNAL:
1455
            {
1456
               printf("%s ", vcode_op_string(op->kind));
1457
               vcode_dump_reg(op->args.items[0]);
1458
               printf(" to ");
1459
               vcode_dump_reg(op->args.items[1]);
1460
               printf(" count ");
1461
               vcode_dump_reg(op->args.items[2]);
1462
               printf(" reject ");
1463
               vcode_dump_reg(op->args.items[3]);
1464
               printf(" after ");
1465
               vcode_dump_reg(op->args.items[4]);
1466
            }
1467
            break;
1468

1469
         case VCODE_OP_RESOLVE_SIGNAL:
1470
            {
1471
               printf("%s ", vcode_op_string(op->kind));
1472
               vcode_dump_reg(op->args.items[0]);
1473
               printf(" resolution ");
1474
               vcode_dump_reg(op->args.items[1]);
1475
            }
1476
            break;
1477

1478
         case VCODE_OP_PACKAGE_SCOPE:
1479
         case VCODE_OP_ARRAY_SCOPE:
1480
         case VCODE_OP_RECORD_SCOPE:
1481
            {
1482
               col += printf("%s locus ", vcode_op_string(op->kind));
1483
               col += vcode_dump_reg(op->args.items[0]);
1484
               vcode_dump_type(col, op->type, VCODE_INVALID_STAMP);
1485
            }
1486
            break;
1487

1488
         case VCODE_OP_POP_SCOPE:
1489
            {
1490
               printf("%s", vcode_op_string(op->kind));
1491
            }
1492
            break;
1493

1494
         case VCODE_OP_INIT_SIGNAL:
1495
            {
1496
               col += vcode_dump_reg(op->result);
1497
               col += printf(" := ");
1498
               col += printf("%s count ", vcode_op_string(op->kind));
1499
               col += vcode_dump_reg(op->args.items[0]);
1500
               col += printf(" size ");
1501
               col += vcode_dump_reg(op->args.items[1]);
1502
               col += printf(" value ");
1503
               col += vcode_dump_reg(op->args.items[2]);
1504
               col += printf(" flags ");
1505
               col += vcode_dump_reg(op->args.items[3]);
1506
               col += printf(" locus ");
1507
               col += vcode_dump_reg(op->args.items[4]);
1508
               if (op->args.count > 5) {
1509
                  col += printf(" offset ");
1510
                  col += vcode_dump_reg(op->args.items[5]);
1511
               }
1512
               vcode_dump_result_type(col, op);
1513
            }
1514
            break;
1515

1516
         case VCODE_OP_IMPLICIT_SIGNAL:
1517
            {
1518
               col += vcode_dump_reg(op->result);
1519
               col += printf(" := %s count ", vcode_op_string(op->kind));
1520
               col += vcode_dump_reg(op->args.items[0]);
1521
               col += printf(" size ");
1522
               col += vcode_dump_reg(op->args.items[1]);
1523
               col += printf(" locus ");
1524
               col += vcode_dump_reg(op->args.items[2]);
1525
               col += printf(" kind ");
1526
               col += vcode_dump_reg(op->args.items[3]);
1527
               col += printf(" closure ");
1528
               col += vcode_dump_reg(op->args.items[4]);
1529
            }
1530
            break;
1531

1532
         case VCODE_OP_RESOLUTION_WRAPPER:
1533
            {
1534
               col += vcode_dump_reg(op->result);
1535
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
1536
               col += vcode_dump_reg(op->args.items[0]);
1537
               col += printf(" nlits ");
1538
               col += vcode_dump_reg(op->args.items[1]);
1539
               vcode_dump_result_type(col, op);
1540
            }
1541
            break;
1542

1543
         case VCODE_OP_CLOSURE:
1544
         case VCODE_OP_PROTECTED_INIT:
1545
            {
1546
               col += vcode_dump_reg(op->result);
1547
               col += nvc_printf(" := %s $magenta$%s$$ context ",
1548
                                 vcode_op_string(op->kind), istr(op->func));
1549
               col += vcode_dump_reg(op->args.items[0]);
1550
               if (op->args.count >= 3) {
1551
                  col += printf(" path " );
1552
                  col += vcode_dump_reg(op->args.items[1]);
1553
                  col += printf(" instance " );
1554
                  col += vcode_dump_reg(op->args.items[2]);
1555
               }
1556
               vcode_dump_result_type(col, op);
1557
            }
1558
            break;
1559

1560
         case VCODE_OP_PACKAGE_INIT:
1561
            {
1562
               col += vcode_dump_reg(op->result);
1563
               col += nvc_printf(" := %s $magenta$%s$$",
1564
                                   vcode_op_string(op->kind), istr(op->func));
1565
               if (op->args.count > 0) {
1566
                  col += printf(" context " );
1567
                  col += vcode_dump_reg(op->args.items[0]);
1568
               }
1569
               vcode_dump_result_type(col, op);
1570
            }
1571
            break;
1572

1573
         case VCODE_OP_PROCESS_INIT:
1574
            {
1575
               nvc_printf("%s $magenta$%s$$ locus ",
1576
                            vcode_op_string(op->kind), istr(op->func));
1577
               vcode_dump_reg(op->args.items[0]);
1578
            }
1579
            break;
1580

1581
         case VCODE_OP_PROTECTED_FREE:
1582
            {
1583
               printf("%s ", vcode_op_string(op->kind));
1584
               vcode_dump_reg(op->args.items[0]);
1585
            }
1586
            break;
1587

1588
         case VCODE_OP_WAIT:
1589
            {
1590
               nvc_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1591
                            op->targets.items[0]);
1592
            }
1593
            break;
1594

1595
         case VCODE_OP_SCHED_PROCESS:
1596
            {
1597
               nvc_printf("%s after ", vcode_op_string(op->kind));
1598
               vcode_dump_reg(op->args.items[0]);
1599
            }
1600
            break;
1601

1602
         case VCODE_OP_JUMP:
1603
            {
1604
               nvc_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1605
                            op->targets.items[0]);
1606
            }
1607
            break;
1608

1609
         case VCODE_OP_COND:
1610
            {
1611
               printf("%s ", vcode_op_string(op->kind));
1612
               vcode_dump_reg(op->args.items[0]);
1613
               nvc_printf(" then $yellow$%d$$ else $yellow$%d$$",
1614
                            op->targets.items[0], op->targets.items[1]);
1615
            }
1616
            break;
1617

1618
         case VCODE_OP_ASSERT:
1619
            {
1620
               printf("%s ", vcode_op_string(op->kind));
1621
               vcode_dump_reg(op->args.items[0]);
1622
               if (op->args.items[2] != VCODE_INVALID_REG) {
1623
                  printf(" report ");
1624
                  vcode_dump_reg(op->args.items[2]);
1625
                  printf(" length ");
1626
                  vcode_dump_reg(op->args.items[3]);
1627
               }
1628
               printf(" severity ");
1629
               vcode_dump_reg(op->args.items[1]);
1630
               printf(" locus ");
1631
               vcode_dump_reg(op->args.items[4]);
1632
               if (op->args.count > 5) {
1633
                  printf(" hint ");
1634
                  vcode_dump_reg(op->args.items[5]);
1635
                  printf(" ");
1636
                  vcode_dump_reg(op->args.items[6]);
1637
               }
1638
            }
1639
            break;
1640

1641
         case VCODE_OP_REPORT:
1642
            {
1643
               printf("%s ", vcode_op_string(op->kind));
1644
               vcode_dump_reg(op->args.items[1]);
1645
               printf(" length ");
1646
               vcode_dump_reg(op->args.items[2]);
1647
               printf(" severity ");
1648
               vcode_dump_reg(op->args.items[0]);
1649
               printf(" locus ");
1650
               vcode_dump_reg(op->args.items[3]);
1651
            }
1652
            break;
1653

1654
         case VCODE_OP_LOAD:
1655
            {
1656
               col += vcode_dump_reg(op->result);
1657
               col += printf(" := %s ", vcode_op_string(op->kind));
1658
               col += vcode_dump_var(op->address, 0);
1659
               vcode_dump_result_type(col, op);
1660
            }
1661
            break;
1662

1663
         case VCODE_OP_LOAD_INDIRECT:
1664
            {
1665
               col += vcode_dump_reg(op->result);
1666
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
1667
               col += vcode_dump_reg(op->args.items[0]);
1668
               vcode_dump_result_type(col, op);
1669
            }
1670
            break;
1671

1672
         case VCODE_OP_STORE:
1673
            {
1674
               vcode_dump_var(op->address, 0);
1675
               printf(" := %s ", vcode_op_string(op->kind));
1676
               vcode_dump_reg(op->args.items[0]);
1677
            }
1678
            break;
1679

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

1688
         case VCODE_OP_INDEX:
1689
            {
1690
               col += vcode_dump_reg(op->result);
1691
               col += printf(" := %s ", vcode_op_string(op->kind));
1692
               col += vcode_dump_var(op->address, 0);
1693
               if (op->args.count > 0) {
1694
                  col += printf(" + ");
1695
                  col += vcode_dump_reg(op->args.items[0]);
1696
               }
1697
               vcode_dump_result_type(col, op);
1698
            }
1699
            break;
1700

1701
         case VCODE_OP_MUL:
1702
         case VCODE_OP_ADD:
1703
         case VCODE_OP_SUB:
1704
         case VCODE_OP_DIV:
1705
         case VCODE_OP_EXP:
1706
         case VCODE_OP_MOD:
1707
         case VCODE_OP_REM:
1708
         case VCODE_OP_OR:
1709
         case VCODE_OP_AND:
1710
         case VCODE_OP_XOR:
1711
         case VCODE_OP_XNOR:
1712
         case VCODE_OP_NAND:
1713
         case VCODE_OP_NOR:
1714
            {
1715
               col += vcode_dump_reg(op->result);
1716
               col += printf(" := %s ", vcode_op_string(op->kind));
1717
               col += vcode_dump_reg(op->args.items[0]);
1718
               switch (op->kind) {
1719
               case VCODE_OP_MUL:  col += printf(" * "); break;
1720
               case VCODE_OP_ADD:  col += printf(" + "); break;
1721
               case VCODE_OP_SUB:  col += printf(" - "); break;
1722
               case VCODE_OP_DIV:  col += printf(" / "); break;
1723
               case VCODE_OP_EXP:  col += printf(" ** "); break;
1724
               case VCODE_OP_MOD:  col += printf(" %% "); break;
1725
               case VCODE_OP_REM:  col += printf(" %% "); break;
1726
               case VCODE_OP_OR:   col += printf(" || "); break;
1727
               case VCODE_OP_AND:  col += printf(" && "); break;
1728
               case VCODE_OP_XOR:  col += printf(" ^ "); break;
1729
               case VCODE_OP_XNOR: col += printf(" !^ "); break;
1730
               case VCODE_OP_NAND: col += printf(" !& "); break;
1731
               case VCODE_OP_NOR:  col += printf(" !| "); break;
1732
               default: break;
1733
               }
1734
               col += vcode_dump_reg(op->args.items[1]);
1735
               vcode_dump_result_type(col, op);
1736
            }
1737
            break;
1738

1739
         case VCODE_OP_TRAP_ADD:
1740
         case VCODE_OP_TRAP_SUB:
1741
         case VCODE_OP_TRAP_MUL:
1742
         case VCODE_OP_TRAP_EXP:
1743
            {
1744
               col += vcode_dump_reg(op->result);
1745
               col += printf(" := %s ", vcode_op_string(op->kind));
1746
               col += vcode_dump_reg(op->args.items[0]);
1747
               switch (op->kind) {
1748
               case VCODE_OP_TRAP_ADD: col += printf(" + "); break;
1749
               case VCODE_OP_TRAP_SUB: col += printf(" - "); break;
1750
               case VCODE_OP_TRAP_MUL: col += printf(" * "); break;
1751
               case VCODE_OP_TRAP_EXP: col += printf(" ** "); break;
1752
               default: break;
1753
               }
1754
               col += vcode_dump_reg(op->args.items[1]);
1755
               col += printf(" locus ");
1756
               col += vcode_dump_reg(op->args.items[2]);
1757
               vcode_dump_result_type(col, op);
1758
            }
1759
            break;
1760

1761
         case VCODE_OP_NOT:
1762
            {
1763
               col += vcode_dump_reg(op->result);
1764
               col += printf(" := %s ", vcode_op_string(op->kind));
1765
               col += vcode_dump_reg(op->args.items[0]);
1766
               vcode_dump_result_type(col, op);
1767
            }
1768
            break;
1769

1770
         case VCODE_OP_COMMENT:
1771
            {
1772
               nvc_printf("$cyan$// %s$$ ", op->comment);
1773
            }
1774
            break;
1775

1776
         case VCODE_OP_CONST_ARRAY:
1777
         case VCODE_OP_CONST_RECORD:
1778
            {
1779
               col += vcode_dump_reg(op->result);
1780
               col += printf(" := const %c",
1781
                             op->kind == VCODE_OP_CONST_ARRAY ? '[' : '{');
1782
               for (int k = 0; k < op->args.count; k++) {
1783
                  if (k > 0)
1784
                     col += printf(",");
1785
                  col += vcode_dump_reg(op->args.items[k]);
1786
               }
1787

1788
               putchar(op->kind == VCODE_OP_CONST_ARRAY ? ']' : '}');
1789
               vcode_dump_result_type(col + 1, op);
1790
            }
1791
            break;
1792

1793
         case VCODE_OP_CONST_REP:
1794
            {
1795
               col += vcode_dump_reg(op->result);
1796
               col += printf(" := const [");
1797
               col += vcode_dump_reg(op->args.items[0]);
1798
               col += printf("]*%"PRIi64, op->value);
1799
               vcode_dump_result_type(col, op);
1800
            }
1801
            break;
1802

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

1813
         case VCODE_OP_RETURN:
1814
            {
1815
               printf("%s ", vcode_op_string(op->kind));
1816
               if (op->args.count > 0)
1817
                  vcode_dump_reg(op->args.items[0]);
1818
            }
1819
            break;
1820

1821
         case VCODE_OP_SCHED_WAVEFORM:
1822
            {
1823
               printf("%s ", vcode_op_string(op->kind));
1824
               vcode_dump_reg(op->args.items[0]);
1825
               printf(" count ");
1826
               vcode_dump_reg(op->args.items[1]);
1827
               printf(" values ");
1828
               vcode_dump_reg(op->args.items[2]);
1829
               printf(" reject ");
1830
               vcode_dump_reg(op->args.items[3]);
1831
               printf(" after ");
1832
               vcode_dump_reg(op->args.items[4]);
1833
            }
1834
            break;
1835

1836
         case VCODE_OP_FORCE:
1837
         case VCODE_OP_RELEASE:
1838
            {
1839
               printf("%s ", vcode_op_string(op->kind));
1840
               vcode_dump_reg(op->args.items[0]);
1841
               printf(" count ");
1842
               vcode_dump_reg(op->args.items[1]);
1843
               if (op->args.count > 2) {
1844
                  printf(" values ");
1845
                  vcode_dump_reg(op->args.items[2]);
1846
               }
1847
            }
1848
            break;
1849

1850
         case VCODE_OP_DISCONNECT:
1851
            {
1852
               printf("%s ", vcode_op_string(op->kind));
1853
               vcode_dump_reg(op->args.items[0]);
1854
               printf(" count ");
1855
               vcode_dump_reg(op->args.items[1]);
1856
               printf(" reject ");
1857
               vcode_dump_reg(op->args.items[2]);
1858
               printf(" after ");
1859
               vcode_dump_reg(op->args.items[3]);
1860
            }
1861
            break;
1862

1863
         case VCODE_OP_NEG:
1864
         case VCODE_OP_TRAP_NEG:
1865
         case VCODE_OP_ABS:
1866
         case VCODE_OP_RESOLVED:
1867
         case VCODE_OP_LAST_VALUE:
1868
            {
1869
               col += vcode_dump_reg(op->result);
1870
               col += printf(" := %s ", vcode_op_string(op->kind));
1871
               col += vcode_dump_reg(op->args.items[0]);
1872
               if (op->args.count > 1) {
1873
                  col += printf(" locus ");
1874
                  col += vcode_dump_reg(op->args.items[1]);
1875
               }
1876
               vcode_dump_result_type(col, op);
1877
            }
1878
            break;
1879

1880
         case VCODE_OP_SELECT:
1881
            {
1882
               col += vcode_dump_reg(op->result);
1883
               col += printf(" := %s ", vcode_op_string(op->kind));
1884
               col += vcode_dump_reg(op->args.items[0]);
1885
               col += printf(" then ");
1886
               col += vcode_dump_reg(op->args.items[1]);
1887
               col += printf(" else ");
1888
               col += vcode_dump_reg(op->args.items[2]);
1889
               vcode_dump_result_type(col, op);
1890
            }
1891
            break;
1892

1893
         case VCODE_OP_WRAP:
1894
            {
1895
               col += vcode_dump_reg(op->result);
1896
               col += printf(" := %s ", vcode_op_string(op->kind));
1897
               col += vcode_dump_reg(op->args.items[0]);
1898
               col += printf(" [");
1899
               for (int i = 1; i < op->args.count; i += 3) {
1900
                  if (i > 1)
1901
                     col += printf(", ");
1902
                  col += vcode_dump_reg(op->args.items[i + 0]);
1903
                  col += printf(" ");
1904
                  col += vcode_dump_reg(op->args.items[i + 1]);
1905
                  col += printf(" ");
1906
                  col += vcode_dump_reg(op->args.items[i + 2]);
1907
               }
1908
               col += printf("]");
1909
               vcode_dump_result_type(col, op);
1910
            }
1911
            break;
1912

1913
         case VCODE_OP_UARRAY_LEFT:
1914
         case VCODE_OP_UARRAY_RIGHT:
1915
         case VCODE_OP_UARRAY_DIR:
1916
         case VCODE_OP_UARRAY_LEN:
1917
            {
1918
               col += vcode_dump_reg(op->result);
1919
               col += printf(" := %s ", vcode_op_string(op->kind));
1920
               col += vcode_dump_reg(op->args.items[0]);
1921
               col += printf(" dim %d", op->dim);
1922
               vcode_dump_result_type(col, op);
1923
            }
1924
            break;
1925

1926
         case VCODE_OP_UNWRAP:
1927
            {
1928
               col += vcode_dump_reg(op->result);
1929
               col += printf(" := %s ", vcode_op_string(op->kind));
1930
               col += vcode_dump_reg(op->args.items[0]);
1931
               vcode_dump_result_type(col, op);
1932
            }
1933
            break;
1934

1935
         case VCODE_OP_VAR_UPREF:
1936
            {
1937
               col += vcode_dump_reg(op->result);
1938
               col += printf(" := %s %d, ", vcode_op_string(op->kind),
1939
                             op->hops);
1940
               col += vcode_dump_var(op->address, op->hops);
1941
               vcode_dump_result_type(col, op);
1942
            }
1943
            break;
1944

1945
         case VCODE_OP_CONTEXT_UPREF:
1946
            {
1947
               col += vcode_dump_reg(op->result);
1948
               col += printf(" := %s %d", vcode_op_string(op->kind), op->hops);
1949
               vcode_dump_result_type(col, op);
1950
            }
1951
            break;
1952

1953
         case VCODE_OP_ACTIVE:
1954
         case VCODE_OP_EVENT:
1955
         case VCODE_OP_DRIVING:
1956
            {
1957
               col += vcode_dump_reg(op->result);
1958
               col += printf(" := %s ", vcode_op_string(op->kind));
1959
               col += vcode_dump_reg(op->args.items[0]);
1960
               col += printf(" length ");
1961
               col += vcode_dump_reg(op->args.items[1]);
1962
               vcode_dump_result_type(col, op);
1963
            }
1964
            break;
1965

1966
         case VCODE_OP_RECORD_REF:
1967
            {
1968
               col += vcode_dump_reg(op->result);
1969
               col += printf(" := %s ", vcode_op_string(op->kind));
1970
               col += vcode_dump_reg(op->args.items[0]);
1971
               col += printf(" field %d", op->field);
1972
               vcode_dump_result_type(col, op);
1973
            }
1974
            break;
1975

1976
         case VCODE_OP_ARRAY_REF:
1977
            {
1978
               col += vcode_dump_reg(op->result);
1979
               col += printf(" := %s ", vcode_op_string(op->kind));
1980
               col += vcode_dump_reg(op->args.items[0]);
1981
               col += printf(" offset ");
1982
               col += vcode_dump_reg(op->args.items[1]);
1983
               vcode_dump_result_type(col, op);
1984
            }
1985
            break;
1986

1987
         case VCODE_OP_TABLE_REF:
1988
            {
1989
               col += vcode_dump_reg(op->result);
1990
               col += printf(" := %s ", vcode_op_string(op->kind));
1991
               col += vcode_dump_reg(op->args.items[0]);
1992
               col += printf(" stride ");
1993
               col += vcode_dump_reg(op->args.items[1]);
1994
               col += printf(" [");
1995
               for (int i = 2; i < op->args.count; i++) {
1996
                  if (i > 2) col += printf(", ");
1997
                  col += vcode_dump_reg(op->args.items[i]);
1998
               }
1999
               col += printf("]");
2000
               vcode_dump_result_type(col, op);
2001
            }
2002
            break;
2003

2004
         case VCODE_OP_COPY:
2005
            {
2006
               vcode_dump_reg(op->args.items[0]);
2007
               printf(" := %s ", vcode_op_string(op->kind));
2008
               vcode_dump_reg(op->args.items[1]);
2009
               if (op->args.count > 2) {
2010
                  printf(" count " );
2011
                  vcode_dump_reg(op->args.items[2]);
2012
               }
2013
            }
2014
            break;
2015

2016
         case VCODE_OP_SCHED_EVENT:
2017
         case VCODE_OP_CLEAR_EVENT:
2018
            {
2019
               printf("%s on ", vcode_op_string(op->kind));
2020
               vcode_dump_reg(op->args.items[0]);
2021
               printf(" count ");
2022
               vcode_dump_reg(op->args.items[1]);
2023
            }
2024
            break;
2025

2026
         case VCODE_OP_PCALL:
2027
            {
2028
               nvc_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
2029
                          istr(op->func));
2030
               for (int i = 0; i < op->args.count; i++) {
2031
                  printf("%s", i > 0 ? ", " : " ");
2032
                  vcode_dump_reg(op->args.items[i]);
2033
               }
2034
               if (op->targets.count > 0)
2035
                  nvc_printf(" resume $yellow$%d$$", op->targets.items[0]);
2036
            }
2037
            break;
2038

2039
         case VCODE_OP_RESUME:
2040
            {
2041
               nvc_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
2042
                            istr(op->func));
2043
            }
2044
            break;
2045

2046
         case VCODE_OP_MEMSET:
2047
            {
2048
               vcode_dump_reg(op->args.items[0]);
2049
               printf(" := %s ", vcode_op_string(op->kind));
2050
               vcode_dump_reg(op->args.items[1]);
2051
               printf(" length ");
2052
               vcode_dump_reg(op->args.items[2]);
2053
            }
2054
            break;
2055

2056
         case VCODE_OP_CASE:
2057
            {
2058
               printf("%s ", vcode_op_string(op->kind));
2059
               vcode_dump_reg(op->args.items[0]);
2060
               nvc_printf(" default $yellow$%d$$", op->targets.items[0]);
2061
               for (int i = 1; i < op->args.count; i++) {
2062
                  printf(" [");
2063
                  vcode_dump_reg(op->args.items[i]);
2064
                  nvc_printf(" $yellow$%d$$]", op->targets.items[i]);
2065
               }
2066
            }
2067
            break;
2068

2069
         case VCODE_OP_FILE_OPEN:
2070
            {
2071
               printf("%s ", vcode_op_string(op->kind));
2072
               vcode_dump_reg(op->args.items[0]);
2073
               printf(" name ");
2074
               vcode_dump_reg(op->args.items[1]);
2075
               printf(" length ");
2076
               vcode_dump_reg(op->args.items[2]);
2077
               printf(" kind ");
2078
               vcode_dump_reg(op->args.items[3]);
2079
               if (op->args.count == 5) {
2080
                  printf(" status ");
2081
                  vcode_dump_reg(op->args.items[4]);
2082
               }
2083
            }
2084
            break;
2085

2086
         case VCODE_OP_FILE_WRITE:
2087
            {
2088
               printf("%s ", vcode_op_string(op->kind));
2089
               vcode_dump_reg(op->args.items[0]);
2090
               printf(" value ");
2091
               vcode_dump_reg(op->args.items[1]);
2092
               if (op->args.count == 3) {
2093
                  printf(" length ");
2094
                  vcode_dump_reg(op->args.items[2]);
2095
               }
2096
            }
2097
            break;
2098

2099
         case VCODE_OP_FILE_READ:
2100
            {
2101
               printf("%s ", vcode_op_string(op->kind));
2102
               vcode_dump_reg(op->args.items[0]);
2103
               printf(" ptr ");
2104
               vcode_dump_reg(op->args.items[1]);
2105
               if (op->args.count >= 3) {
2106
                  printf(" inlen ");
2107
                  vcode_dump_reg(op->args.items[2]);
2108
                  if (op->args.count >= 4) {
2109
                     printf(" outlen ");
2110
                     vcode_dump_reg(op->args.items[3]);
2111
                  }
2112
               }
2113
            }
2114
            break;
2115

2116
         case VCODE_OP_NULL:
2117
         case VCODE_OP_NEW:
2118
            {
2119
               col += vcode_dump_reg(op->result);
2120
               col += printf(" := %s", vcode_op_string(op->kind));
2121
               if (op->args.count == 1) {
2122
                  col += printf(" length ");
2123
                  col += vcode_dump_reg(op->args.items[0]);
2124
               }
2125
               vcode_dump_result_type(col, op);
2126
            }
2127
            break;
2128

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

2138
         case VCODE_OP_DEALLOCATE:
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_ALL:
2146
            {
2147
               col += vcode_dump_reg(op->result);
2148
               col += printf(" := %s ", vcode_op_string(op->kind));
2149
               col += vcode_dump_reg(op->args.items[0]);
2150
               vcode_dump_result_type(col, op);
2151
            }
2152
            break;
2153

2154
         case VCODE_OP_LAST_EVENT:
2155
         case VCODE_OP_LAST_ACTIVE:
2156
         case VCODE_OP_DRIVING_VALUE:
2157
            {
2158
               col += vcode_dump_reg(op->result);
2159
               col += printf(" := %s ", vcode_op_string(op->kind));
2160
               col += vcode_dump_reg(op->args.items[0]);
2161
               if (op->args.count > 1) {
2162
                  col += printf(" length ");
2163
                  col += vcode_dump_reg(op->args.items[1]);
2164
               }
2165
               vcode_dump_result_type(col, op);
2166
            }
2167
            break;
2168

2169
         case VCODE_OP_ALIAS_SIGNAL:
2170
            {
2171
               printf("%s ", vcode_op_string(op->kind));
2172
               vcode_dump_reg(op->args.items[0]);
2173
               printf(" locus ");
2174
               vcode_dump_reg(op->args.items[1]);
2175
            }
2176
            break;
2177

2178
         case VCODE_OP_LENGTH_CHECK:
2179
            {
2180
               col += printf("%s left ", vcode_op_string(op->kind));
2181
               col += vcode_dump_reg(op->args.items[0]);
2182
               col += printf(" == right ");
2183
               col += vcode_dump_reg(op->args.items[1]);
2184
               col += printf(" locus ");
2185
               col += vcode_dump_reg(op->args.items[2]);
2186
               if (op->args.count > 3) {
2187
                  col += printf(" dim ");
2188
                  col += vcode_dump_reg(op->args.items[3]);
2189
               }
2190
            }
2191
            break;
2192

2193
         case VCODE_OP_EXPONENT_CHECK:
2194
         case VCODE_OP_ZERO_CHECK:
2195
            {
2196
               col += printf("%s ", vcode_op_string(op->kind));
2197
               col += vcode_dump_reg(op->args.items[0]);
2198
               col += printf(" locus ");
2199
               col += vcode_dump_reg(op->args.items[1]);
2200
            }
2201
            break;
2202

2203
         case VCODE_OP_INDEX_CHECK:
2204
         case VCODE_OP_RANGE_CHECK:
2205
            {
2206
               col += printf("%s ", vcode_op_string(op->kind));
2207
               col += vcode_dump_reg(op->args.items[0]);
2208
               col += printf(" left ");
2209
               col += vcode_dump_reg(op->args.items[1]);
2210
               col += printf(" right ");
2211
               col += vcode_dump_reg(op->args.items[2]);
2212
               col += printf(" dir ");
2213
               col += vcode_dump_reg(op->args.items[3]);
2214
               col += printf(" locus ");
2215
               col += vcode_dump_reg(op->args.items[4]);
2216
               if (op->args.items[5] != op->args.items[4]) {
2217
                  col += printf(" hint ");
2218
                  col += vcode_dump_reg(op->args.items[5]);
2219
               }
2220
            }
2221
            break;
2222

2223
         case VCODE_OP_DIR_CHECK:
2224
            {
2225
               col += printf("%s ", vcode_op_string(op->kind));
2226
               col += vcode_dump_reg(op->args.items[0]);
2227
               col += printf(" == ");
2228
               col += vcode_dump_reg(op->args.items[1]);
2229
               col += printf(" locus ");
2230
               col += vcode_dump_reg(op->args.items[2]);
2231
            }
2232
            break;
2233

2234
         case VCODE_OP_DEBUG_OUT:
2235
            {
2236
               col += printf("%s ", vcode_op_string(op->kind));
2237
               col += vcode_dump_reg(op->args.items[0]);
2238
            }
2239
            break;
2240

2241
         case VCODE_OP_COVER_STMT:
2242
         case VCODE_OP_COVER_BRANCH:
2243
         case VCODE_OP_COVER_EXPR:
2244
            {
2245
               printf("%s ", vcode_op_string(op->kind));
2246
               vcode_dump_reg(op->args.items[0]);
2247
               printf("+%u", op->tag);
2248
            }
2249
            break;
2250

2251
         case VCODE_OP_COVER_TOGGLE:
2252
         case VCODE_OP_COVER_STATE:
2253
            {
2254
               printf("%s ", vcode_op_string(op->kind));
2255
               vcode_dump_reg(op->args.items[0]);
2256
               printf("+%u ", op->tag);
2257
               vcode_dump_reg(op->args.items[1]);
2258
            }
2259
            break;
2260

2261
         case VCODE_OP_UNDEFINED:
2262
            {
2263
               col += vcode_dump_reg(op->result);
2264
               col += printf(" := %s", vcode_op_string(op->kind));
2265
               vcode_dump_result_type(col, op);
2266
            }
2267
            break;
2268

2269
         case VCODE_OP_RANGE_LENGTH:
2270
         case VCODE_OP_RANGE_NULL:
2271
            {
2272
               col += vcode_dump_reg(op->result);
2273
               col += printf(" := %s left ", vcode_op_string(op->kind));
2274
               vcode_dump_reg(op->args.items[0]);
2275
               col += printf(" right ");
2276
               vcode_dump_reg(op->args.items[1]);
2277
               col += printf(" dir ");
2278
               col += vcode_dump_reg(op->args.items[2]);
2279
               vcode_dump_result_type(col, op);
2280
            }
2281
            break;
2282

2283
         case VCODE_OP_LINK_PACKAGE:
2284
            {
2285
               col += vcode_dump_reg(op->result);
2286
               col += nvc_printf(" := %s $magenta$%s$$",
2287
                                 vcode_op_string(op->kind), istr(op->ident));
2288
               if (op->args.count > 0) {
2289
                  col += printf(" locus ");
2290
                  col += vcode_dump_reg(op->args.items[0]);
2291
               }
2292
               vcode_dump_result_type(col, op);
2293
            }
2294
            break;
2295

2296
         case VCODE_OP_LINK_VAR:
2297
            {
2298
               col += vcode_dump_reg(op->result);
2299
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
2300
               col += vcode_dump_reg(op->args.items[0]);
2301
               col += nvc_printf(" $magenta$%s$$", istr(op->ident));
2302
               vcode_dump_result_type(col, op);
2303
            }
2304
            break;
2305

2306
         case VCODE_OP_UNREACHABLE:
2307
            {
2308
               printf("%s", vcode_op_string(op->kind));
2309
               if (op->args.count > 0) {
2310
                  printf(" ");
2311
                  vcode_dump_reg(op->args.items[0]);
2312
               }
2313
            }
2314
            break;
2315

2316
         case VCODE_OP_DEBUG_LOCUS:
2317
            {
2318
               col += vcode_dump_reg(op->result);
2319
               col += nvc_printf(" := %s $magenta$", vcode_op_string(op->kind));
2320

2321
               tree_t t = tree_from_object(op->object);
2322
               if (t != NULL)
2323
                  col += printf("%s@", tree_kind_str(tree_kind(t)));
2324

2325
               col += nvc_printf("%p$$", op->object);
2326
               vcode_dump_result_type(col, op);
2327
            }
2328
            break;
2329

2330
         case VCODE_OP_ENTER_STATE:
2331
            {
2332
               printf("%s ", vcode_op_string(op->kind));
2333
               vcode_dump_reg(op->args.items[0]);
2334
               if (op->args.count > 1) {
2335
                  printf(" strong ");
2336
                  vcode_dump_reg(op->args.items[1]);
2337
               }
2338
            }
2339
            break;
2340

2341
         case VCODE_OP_REFLECT_VALUE:
2342
            {
2343
               col += vcode_dump_reg(op->result);
2344
               col += printf(" := %s ", vcode_op_string(op->kind));
2345
               vcode_dump_reg(op->args.items[0]);
2346
               col += printf(" context ");
2347
               vcode_dump_reg(op->args.items[1]);
2348
               col += printf(" locus ");
2349
               col += vcode_dump_reg(op->args.items[2]);
2350
               if (op->args.count > 3) {
2351
                  col += printf(" bounds ");
2352
                  col += vcode_dump_reg(op->args.items[3]);
2353
               }
2354
               vcode_dump_result_type(col, op);
2355
            }
2356
            break;
2357

2358
         case VCODE_OP_REFLECT_SUBTYPE:
2359
            {
2360
               col += vcode_dump_reg(op->result);
2361
               col += printf(" := %s context ", vcode_op_string(op->kind));
2362
               vcode_dump_reg(op->args.items[0]);
2363
               col += printf(" locus ");
2364
               col += vcode_dump_reg(op->args.items[1]);
2365
               if (op->args.count > 2) {
2366
                  col += printf(" bounds ");
2367
                  col += vcode_dump_reg(op->args.items[2]);
2368
               }
2369
               vcode_dump_result_type(col, op);
2370
            }
2371
            break;
2372

2373
         case VCODE_OP_FUNCTION_TRIGGER:
2374
            {
2375
               col += vcode_dump_reg(op->result);
2376
               col += nvc_printf(" := %s $magenta$%s$$ ",
2377
                                 vcode_op_string(op->kind), istr(op->func));
2378
               for (int i = 0; i < op->args.count; i++) {
2379
                  if (i > 0) col += printf(", ");
2380
                  col += vcode_dump_reg(op->args.items[i]);
2381
               }
2382
               vcode_dump_result_type(col, op);
2383
            }
2384
            break;
2385

2386
         case VCODE_OP_OR_TRIGGER:
2387
         case VCODE_OP_CMP_TRIGGER:
2388
            {
2389
               col += vcode_dump_reg(op->result);
2390
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
2391
               col += vcode_dump_reg(op->args.items[0]);
2392
               if (op->kind == VCODE_OP_OR_TRIGGER)
2393
                  col += printf(" || ");
2394
               else
2395
                  col += printf(" == ");
2396
               col += vcode_dump_reg(op->args.items[1]);
2397
               vcode_dump_result_type(col, op);
2398
            }
2399
            break;
2400

2401
         case VCODE_OP_ADD_TRIGGER:
2402
            {
2403
               printf("%s ", vcode_op_string(op->kind));
2404
               vcode_dump_reg(op->args.items[0]);
2405
            }
2406
            break;
2407

2408
         case VCODE_OP_PUT_CONVERSION:
2409
            {
2410
               nvc_printf("%s ", vcode_op_string(op->kind));
2411
               vcode_dump_reg(op->args.items[0]);
2412
               printf(" signal ");
2413
               vcode_dump_reg(op->args.items[1]);
2414
               printf(" count ");
2415
               vcode_dump_reg(op->args.items[2]);
2416
               printf(" values ");
2417
               vcode_dump_reg(op->args.items[3]);
2418
            }
2419
            break;
2420

2421
         case VCODE_OP_PORT_CONVERSION:
2422
            {
2423
               col += vcode_dump_reg(op->result);
2424
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
2425
               col += vcode_dump_reg(op->args.items[0]);
2426
               if (op->args.count > 1) {
2427
                  col += printf(" effective ");
2428
                  col += vcode_dump_reg(op->args.items[1]);
2429
               }
2430
               vcode_dump_result_type(col, op);
2431
            }
2432
            break;
2433

2434
         case VCODE_OP_CONVERT_IN:
2435
         case VCODE_OP_CONVERT_OUT:
2436
            {
2437
               nvc_printf("%s ", vcode_op_string(op->kind));
2438
               vcode_dump_reg(op->args.items[0]);
2439
               printf(" signal ");
2440
               vcode_dump_reg(op->args.items[1]);
2441
               printf(" count ");
2442
               vcode_dump_reg(op->args.items[2]);
2443
            }
2444
            break;
2445

2446
         case VCODE_OP_BIND_FOREIGN:
2447
            {
2448
               nvc_printf("%s ", vcode_op_string(op->kind));
2449
               vcode_dump_reg(op->args.items[0]);
2450
               printf(" length ");
2451
               vcode_dump_reg(op->args.items[1]);
2452
               if (op->args.count > 2) {
2453
                  printf(" locus ");
2454
                  vcode_dump_reg(op->args.items[1]);
2455
               }
2456
            }
2457
            break;
2458

2459
         case VCODE_OP_INSTANCE_NAME:
2460
         case VCODE_OP_BIND_EXTERNAL:
2461
            {
2462
               col += vcode_dump_reg(op->result);
2463
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
2464
               col += vcode_dump_reg(op->args.items[0]);
2465
               col += nvc_printf(" scope $magenta$%s$$ ", istr(op->ident));
2466
               for (int i = 1; i < op->args.count; i++) {
2467
                  if (i > 1) col += printf(", ");
2468
                  col += vcode_dump_reg(op->args.items[i]);
2469
               }
2470
               vcode_dump_result_type(col, op);
2471
            }
2472
            break;
2473

2474
         case VCODE_OP_GET_COUNTERS:
2475
            {
2476
               col += vcode_dump_reg(op->result);
2477
               col += nvc_printf(":= %s $magenta$%s$$",
2478
                                 vcode_op_string(op->kind), istr(op->ident));
2479
               vcode_dump_result_type(col, op);
2480
            }
2481
            break;
2482
         }
2483

2484
         if (j == mark_op && i == old_block)
2485
            nvc_printf("\t $red$<----$$");
2486

2487
         nvc_printf("$$\n");
2488

2489
         if (callback != NULL)
2490
            (*callback)(j, arg);
2491
      }
2492

2493
      if (b->ops.count == 0)
2494
         nvc_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2495
   }
2496

2497
   printf("\n");
2498
   fflush(stdout);
2499

2500
   active_block = old_block;
2501
}
2502
LCOV_EXCL_STOP
2503

2504
static inline bool vtype_eq_internal(const vtype_t *at, const vtype_t *bt)
13,878,070✔
2505
{
2506
   if (at->kind != bt->kind)
13,878,070✔
2507
      return false;
2508

2509
   switch (at->kind) {
3,720,441✔
2510
   case VCODE_TYPE_INT:
2,471,173✔
2511
      return (at->low == bt->low) && (at->high == bt->high);
3,603,277✔
2512
   case VCODE_TYPE_REAL:
55,769✔
2513
      return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
55,815✔
2514
   case VCODE_TYPE_CARRAY:
102,600✔
2515
      return at->size == bt->size && vtype_eq(at->elem, bt->elem);
109,903✔
2516
   case VCODE_TYPE_UARRAY:
80,017✔
2517
      return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
100,324✔
2518
   case VCODE_TYPE_POINTER:
479,676✔
2519
   case VCODE_TYPE_ACCESS:
2520
      return vtype_eq(at->pointed, bt->pointed);
479,676✔
2521
   case VCODE_TYPE_OFFSET:
2522
   case VCODE_TYPE_OPAQUE:
2523
   case VCODE_TYPE_DEBUG_LOCUS:
2524
   case VCODE_TYPE_TRIGGER:
2525
   case VCODE_TYPE_CONVERSION:
2526
      return true;
2527
   case VCODE_TYPE_RESOLUTION:
73,970✔
2528
   case VCODE_TYPE_CLOSURE:
2529
   case VCODE_TYPE_SIGNAL:
2530
   case VCODE_TYPE_FILE:
2531
      return vtype_eq(at->base, bt->base);
73,970✔
2532
   case VCODE_TYPE_RECORD:
56,691✔
2533
   case VCODE_TYPE_CONTEXT:
2534
      return at->name == bt->name;
56,691✔
UNCOV
2535
   default:
×
2536
      should_not_reach_here();
2537
   }
2538
}
2539

2540
bool vtype_eq(vcode_type_t a, vcode_type_t b)
4,584,452✔
2541
{
2542
   assert(active_unit != NULL);
4,584,452✔
2543

2544
   if (a == b)
4,584,452✔
2545
      return true;
2546
   else if (MASK_CONTEXT(a) == MASK_CONTEXT(b))
952,115✔
2547
      return false;   // Guaranteed by vtype_new
2548
   else {
2549
      const vtype_t *at = vcode_type_data(a);
119,309✔
2550
      const vtype_t *bt = vcode_type_data(b);
119,309✔
2551

2552
      return vtype_eq_internal(at, bt);
119,309✔
2553
   }
2554
}
2555

UNCOV
2556
void vcode_dump(void)
×
2557
{
UNCOV
2558
   vcode_dump_with_mark(-1, NULL, NULL);
×
UNCOV
2559
}
×
2560

2561
static vcode_type_t vtype_new(vtype_t *new)
2,381,676✔
2562
{
2563
   const int index = active_unit->types.count - 1;
2,381,676✔
2564

2565
   for (int i = 0; i < index; i++) {
14,088,592✔
2566
      const vtype_t *cmp = vtype_array_nth_ptr(&(active_unit->types), i);
13,758,761✔
2567
      if (vtype_eq_internal(new, cmp)) {
13,758,761✔
2568
         active_unit->types.count--;
2,051,845✔
2569
         return MAKE_HANDLE(active_unit->depth, i);
2,051,845✔
2570
      }
2571
   }
2572

2573
   return MAKE_HANDLE(active_unit->depth, index);
329,831✔
2574
}
2575

2576
vcode_type_t vtype_int(int64_t low, int64_t high)
1,404,210✔
2577
{
2578
   assert(active_unit != NULL);
1,404,210✔
2579

2580
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,404,210✔
2581
   n->kind = VCODE_TYPE_INT;
1,404,210✔
2582
   n->low  = low;
1,404,210✔
2583
   n->high = high;
1,404,210✔
2584

2585
   switch (bits_for_range(low, high)) {
1,404,210✔
2586
   case 64:
57,275✔
2587
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
57,275✔
2588
      break;
57,275✔
2589
   case 32:
364,838✔
2590
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
364,838✔
2591
      break;
364,838✔
2592
   case 16:
123✔
2593
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
123✔
2594
      break;
123✔
2595
   case 8:
550,226✔
2596
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
550,226✔
2597
      break;
550,226✔
2598
   case 1:
431,748✔
2599
      n->repr = VCODE_REPR_U1;
431,748✔
2600
      break;
431,748✔
UNCOV
2601
   case 0:
×
UNCOV
2602
      n->repr = VCODE_REPR_I64;    // Null range
×
UNCOV
2603
      break;
×
UNCOV
2604
   default:
×
2605
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2606
   }
2607

2608
   return vtype_new(n);
1,404,210✔
2609
}
2610

2611
vcode_type_t vtype_bool(void)
336,115✔
2612
{
2613
   return vtype_int(0, 1);
336,115✔
2614
}
2615

2616
vcode_type_t vtype_carray(int size, vcode_type_t elem)
56,190✔
2617
{
2618
   assert(active_unit != NULL);
56,190✔
2619

2620
   const vtype_kind_t ekind = vtype_kind(elem);
56,190✔
2621
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
56,190✔
2622
                "array types may not be nested");
2623

2624
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
56,190✔
2625
   memset(n, '\0', sizeof(vtype_t));
56,190✔
2626
   n->kind   = VCODE_TYPE_CARRAY;
56,190✔
2627
   n->elem   = elem;
56,190✔
2628
   n->size   = MAX(size, 0);
56,190✔
2629

2630
   return vtype_new(n);
56,190✔
2631
}
2632

2633
vcode_type_t vtype_find_named_record(ident_t name)
29,249✔
2634
{
2635
   assert(active_unit != NULL);
29,249✔
2636

2637
   for (int i = 0; i < active_unit->types.count; i++) {
267,047✔
2638
      vtype_t *other = &(active_unit->types.items[i]);
255,431✔
2639
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
255,431✔
2640
         return MAKE_HANDLE(active_unit->depth, i);
17,633✔
2641
   }
2642

2643
   return VCODE_INVALID_TYPE;
2644
}
2645

2646
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
11,616✔
2647
                                int nfields)
2648
{
2649
   assert(active_unit != NULL);
11,616✔
2650

2651
   vtype_t *data = NULL;
11,616✔
2652
   vcode_type_t handle = vtype_find_named_record(name);
11,616✔
2653
   if (handle == VCODE_INVALID_TYPE) {
11,616✔
2654
      data = vtype_array_alloc(&(active_unit->types));
5,808✔
2655
      memset(data, '\0', sizeof(vtype_t));
5,808✔
2656
      data->kind = VCODE_TYPE_RECORD;
5,808✔
2657
      data->name = name;
5,808✔
2658

2659
      handle = vtype_new(data);
5,808✔
2660
   }
2661
   else {
2662
      data = vcode_type_data(handle);
5,808✔
2663
      VCODE_ASSERT(data->fields.count == 0,
5,808✔
2664
                    "record type %s already defined", istr(name));
2665
   }
2666

2667
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
11,616✔
2668
   for (int i = 0; i < nfields; i++)
30,828✔
2669
      vcode_type_array_add(&(data->fields), field_types[i]);
19,212✔
2670

2671
   return handle;
11,616✔
2672
}
2673

2674
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem)
76,733✔
2675
{
2676
   assert(active_unit != NULL);
76,733✔
2677

2678
   const vtype_kind_t ekind = vtype_kind(elem);
76,733✔
2679
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
76,733✔
2680
                "array types may not be nested");
2681

2682
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
76,733✔
2683

2684
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
76,733✔
2685
   memset(n, '\0', sizeof(vtype_t));
76,733✔
2686
   n->kind = VCODE_TYPE_UARRAY;
76,733✔
2687
   n->elem = elem;
76,733✔
2688
   n->dims = ndim;
76,733✔
2689

2690
   return vtype_new(n);
76,733✔
2691
}
2692

2693
vcode_type_t vtype_pointer(vcode_type_t to)
205,223✔
2694
{
2695
   assert(active_unit != NULL);
205,223✔
2696

2697
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
205,223✔
2698
   n->kind    = VCODE_TYPE_POINTER;
205,223✔
2699
   n->pointed = to;
205,223✔
2700

2701
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
205,223✔
2702
                "cannot get pointer to carray type");
2703

2704
   return vtype_new(n);
205,223✔
2705
}
2706

2707
vcode_type_t vtype_access(vcode_type_t to)
6,606✔
2708
{
2709
   assert(active_unit != NULL);
6,606✔
2710

2711
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
6,606✔
2712
   n->kind    = VCODE_TYPE_ACCESS;
6,606✔
2713
   n->pointed = to;
6,606✔
2714

2715
   return vtype_new(n);
6,606✔
2716
}
2717

2718
vcode_type_t vtype_signal(vcode_type_t base)
39,926✔
2719
{
2720
   assert(active_unit != NULL);
39,926✔
2721

2722
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
39,926✔
2723
   n->kind = VCODE_TYPE_SIGNAL;
39,926✔
2724
   n->base = base;
39,926✔
2725

2726
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
39,926✔
2727

2728
   return vtype_new(n);
39,926✔
2729
}
2730

2731
vcode_type_t vtype_resolution(vcode_type_t base)
8,403✔
2732
{
2733
   assert(active_unit != NULL);
8,403✔
2734

2735
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
8,403✔
2736
   n->kind = VCODE_TYPE_RESOLUTION;
8,403✔
2737
   n->base = base;
8,403✔
2738

2739
   return vtype_new(n);
8,403✔
2740
}
2741

2742
vcode_type_t vtype_closure(vcode_type_t result)
5,510✔
2743
{
2744
   assert(active_unit != NULL);
5,510✔
2745

2746
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
5,510✔
2747
   n->kind = VCODE_TYPE_CLOSURE;
5,510✔
2748
   n->base = result;
5,510✔
2749

2750
   return vtype_new(n);
5,510✔
2751
}
2752

2753
vcode_type_t vtype_context(ident_t name)
54,390✔
2754
{
2755
   assert(active_unit != NULL);
54,390✔
2756
   assert(name != NULL);
54,390✔
2757

2758
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
54,390✔
2759
   n->kind = VCODE_TYPE_CONTEXT;
54,390✔
2760
   n->name = name;
54,390✔
2761

2762
   return vtype_new(n);
54,390✔
2763
}
2764

2765
vcode_type_t vtype_file(vcode_type_t base)
1,611✔
2766
{
2767
   assert(active_unit != NULL);
1,611✔
2768

2769
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,611✔
2770
   n->kind = VCODE_TYPE_FILE;
1,611✔
2771
   n->base = base;
1,611✔
2772

2773
   return vtype_new(n);
1,611✔
2774
}
2775

2776
vcode_type_t vtype_offset(void)
293,679✔
2777
{
2778
   assert(active_unit != NULL);
293,679✔
2779

2780
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
293,679✔
2781
   n->kind = VCODE_TYPE_OFFSET;
293,679✔
2782
   n->low  = INT64_MIN;
293,679✔
2783
   n->high = INT64_MAX;
293,679✔
2784
   n->repr = VCODE_REPR_I64;
293,679✔
2785

2786
   return vtype_new(n);
293,679✔
2787
}
2788

2789
vcode_type_t vtype_time(void)
14,388✔
2790
{
2791
   return vtype_int(INT64_MIN, INT64_MAX);
14,388✔
2792
}
2793

2794
vcode_type_t vtype_char(void)
8,111✔
2795
{
2796
   return vtype_int(0, 255);
8,111✔
2797
}
2798

2799
vcode_type_t vtype_opaque(void)
2,395✔
2800
{
2801
   assert(active_unit != NULL);
2,395✔
2802

2803
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
2,395✔
2804
   n->kind = VCODE_TYPE_OPAQUE;
2,395✔
2805

2806
   return vtype_new(n);
2,395✔
2807
}
2808

2809
vcode_type_t vtype_debug_locus(void)
157,238✔
2810
{
2811
   assert(active_unit != NULL);
157,238✔
2812

2813
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
157,238✔
2814
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
157,238✔
2815

2816
   return vtype_new(n);
157,238✔
2817
}
2818

2819
vcode_type_t vtype_trigger(void)
385✔
2820
{
2821
   assert(active_unit != NULL);
385✔
2822

2823
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
385✔
2824
   n->kind = VCODE_TYPE_TRIGGER;
385✔
2825

2826
   return vtype_new(n);
385✔
2827
}
2828

2829
vcode_type_t vtype_conversion(void)
426✔
2830
{
2831
   assert(active_unit != NULL);
426✔
2832

2833
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
426✔
2834
   n->kind = VCODE_TYPE_CONVERSION;
426✔
2835

2836
   return vtype_new(n);
426✔
2837
}
2838

2839
vcode_type_t vtype_real(double low, double high)
62,943✔
2840
{
2841
   assert(active_unit != NULL);
62,943✔
2842

2843
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
62,943✔
2844
   n->kind  = VCODE_TYPE_REAL;
62,943✔
2845
   n->rlow  = low;
62,943✔
2846
   n->rhigh = high;
62,943✔
2847

2848
   return vtype_new(n);
62,943✔
2849
}
2850

2851
vtype_kind_t vtype_kind(vcode_type_t type)
3,923,706✔
2852
{
2853
   vtype_t *vt = vcode_type_data(type);
3,923,706✔
2854
   return vt->kind;
3,923,706✔
2855
}
2856

2857
vtype_repr_t vtype_repr(vcode_type_t type)
42,453✔
2858
{
2859
   vtype_t *vt = vcode_type_data(type);
42,453✔
2860
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
42,453✔
2861
   return vt->repr;
42,453✔
2862
}
2863

2864
vcode_type_t vtype_elem(vcode_type_t type)
128,201✔
2865
{
2866
   vtype_t *vt = vcode_type_data(type);
128,201✔
2867
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
128,201✔
2868
   return vt->elem;
128,201✔
2869
}
2870

2871
vcode_type_t vtype_base(vcode_type_t type)
53,016✔
2872
{
2873
   vtype_t *vt = vcode_type_data(type);
53,016✔
2874
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
53,016✔
2875
          || vt->kind == VCODE_TYPE_RESOLUTION
2876
          || vt->kind == VCODE_TYPE_CLOSURE);
2877
   return vt->base;
53,016✔
2878
}
2879

2880
unsigned vtype_dims(vcode_type_t type)
43,218✔
2881
{
2882
   vtype_t *vt = vcode_type_data(type);
43,218✔
2883
   assert(vt->kind == VCODE_TYPE_UARRAY);
43,218✔
2884
   return vt->dims;
43,218✔
2885
}
2886

2887
unsigned vtype_size(vcode_type_t type)
52,747✔
2888
{
2889
   vtype_t *vt = vcode_type_data(type);
52,747✔
2890
   assert(vt->kind == VCODE_TYPE_CARRAY);
52,747✔
2891
   return vt->size;
52,747✔
2892
}
2893

2894
int vtype_fields(vcode_type_t type)
8,099✔
2895
{
2896
   vtype_t *vt = vcode_type_data(type);
8,099✔
2897
   assert(vt->kind == VCODE_TYPE_RECORD);
8,099✔
2898
   return vt->fields.count;
8,099✔
2899
}
2900

2901
vcode_type_t vtype_field(vcode_type_t type, int field)
31,242✔
2902
{
2903
   vtype_t *vt = vcode_type_data(type);
31,242✔
2904
   assert(vt->kind == VCODE_TYPE_RECORD);
31,242✔
2905
   return vcode_type_array_nth(&(vt->fields), field);
31,242✔
2906
}
2907

2908
ident_t vtype_name(vcode_type_t type)
19,243✔
2909
{
2910
   vtype_t *vt = vcode_type_data(type);
19,243✔
2911
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
19,243✔
2912
   return vt->name;
19,243✔
2913
}
2914

2915
vcode_type_t vtype_pointed(vcode_type_t type)
340,886✔
2916
{
2917
   vtype_t *vt = vcode_type_data(type);
340,886✔
2918
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
340,886✔
2919
   return vt->pointed;
340,886✔
2920
}
2921

2922
int64_t vtype_low(vcode_type_t type)
82,779✔
2923
{
2924
   vtype_t *vt = vcode_type_data(type);
82,779✔
2925
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
82,779✔
2926
   return vt->low;
82,779✔
2927
}
2928

2929
int64_t vtype_high(vcode_type_t type)
83,380✔
2930
{
2931
   vtype_t *vt = vcode_type_data(type);
83,380✔
2932
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
83,380✔
2933
   return vt->high;
83,380✔
2934
}
2935

2936
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
1,593✔
2937
{
2938
   return vtype_kind(type) == VCODE_TYPE_POINTER
1,593✔
2939
      && vtype_kind(vtype_pointed(type)) == to;
1,593✔
2940
}
2941

2942
bool vtype_is_scalar(vcode_type_t type)
422,572✔
2943
{
2944
   const vtype_kind_t kind = vtype_kind(type);
422,572✔
2945
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
422,572✔
2946
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
164,702✔
2947
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2948
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2949
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER
2950
      || kind == VCODE_TYPE_RESOLUTION;
422,572✔
2951
}
2952

2953
bool vtype_is_numeric(vcode_type_t type)
18,815✔
2954
{
2955
   const vtype_kind_t kind = vtype_kind(type);
18,815✔
2956
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
18,815✔
2957
      || kind == VCODE_TYPE_REAL;
18,815✔
2958
}
2959

2960
bool vtype_is_integral(vcode_type_t type)
1,035✔
2961
{
2962
   const vtype_kind_t kind = vtype_kind(type);
1,035✔
2963
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET;
1,035✔
2964
}
2965

2966
bool vtype_is_composite(vcode_type_t type)
32,030✔
2967
{
2968
   const vtype_kind_t kind = vtype_kind(type);
32,030✔
2969
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
32,030✔
2970
}
2971

2972
bool vtype_is_signal(vcode_type_t type)
154,373✔
2973
{
2974
   vtype_t *vt = vcode_type_data(type);
276,278✔
2975
   switch (vt->kind) {
276,278✔
2976
   case VCODE_TYPE_SIGNAL:
2977
      return true;
2978
   case VCODE_TYPE_POINTER:
71,663✔
2979
      return vtype_is_signal(vt->pointed);
71,663✔
2980
   case VCODE_TYPE_RECORD:
2981
      for (int i = 0; i < vt->fields.count; i++) {
34,480✔
2982
         if (vtype_is_signal(vt->fields.items[i]))
27,276✔
2983
            return true;
2984
      }
2985
      return false;
2986
   case VCODE_TYPE_UARRAY:
50,242✔
2987
   case VCODE_TYPE_CARRAY:
2988
      return vtype_is_signal(vt->elem);
50,242✔
2989
   default:
119,670✔
2990
      return false;
119,670✔
2991
   }
2992
}
2993

2994
int vtype_repr_bits(vtype_repr_t repr)
×
2995
{
UNCOV
2996
   switch (repr) {
×
2997
   case VCODE_REPR_U1: return 1;
2998
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2999
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
3000
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
3001
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
3002
   default: return -1;
3003
   }
3004
}
3005

UNCOV
3006
bool vtype_repr_signed(vtype_repr_t repr)
×
3007
{
UNCOV
3008
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
×
UNCOV
3009
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
×
3010
}
3011

3012
static int64_t vtype_repr_low(vtype_repr_t repr)
13,734✔
3013
{
3014
   switch (repr) {
13,734✔
3015
   case VCODE_REPR_U1:
3016
   case VCODE_REPR_U8:
3017
   case VCODE_REPR_U16:
3018
   case VCODE_REPR_U32:
3019
   case VCODE_REPR_U64: return 0;
3020
   case VCODE_REPR_I8:  return INT8_MIN;
3021
   case VCODE_REPR_I16: return INT16_MIN;
3022
   case VCODE_REPR_I32: return INT32_MIN;
3023
   case VCODE_REPR_I64: return INT64_MIN;
3024
   default:             return 0;
3025
   }
3026
}
3027

3028
static uint64_t vtype_repr_high(vtype_repr_t repr)
13,734✔
3029
{
3030
   switch (repr) {
13,734✔
3031
   case VCODE_REPR_U1:  return 1;
3032
   case VCODE_REPR_U8:  return UINT8_MAX;
3033
   case VCODE_REPR_U16: return UINT16_MAX;
3034
   case VCODE_REPR_U32: return UINT32_MAX;
3035
   case VCODE_REPR_U64: return UINT64_MAX;
3036
   case VCODE_REPR_I8:  return INT8_MAX;
3037
   case VCODE_REPR_I16: return INT16_MAX;
3038
   case VCODE_REPR_I32: return INT32_MAX;
3039
   case VCODE_REPR_I64: return INT64_MAX;
3040
   default:             return 0;
3041
   }
3042
}
3043

3044
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
13,734✔
3045
{
3046
   int64_t clamp_low = vtype_repr_low(repr);
13,734✔
3047
   uint64_t clamp_high = vtype_repr_high(repr);
13,734✔
3048

3049
   if (*low >= clamp_low && *high <= clamp_high)
13,734✔
3050
      return true;
3051
   else {
3052
      *low = MAX(clamp_low, *low);
7,001✔
3053
      *high = MIN(clamp_high, *high);
7,001✔
3054
      return false;
7,001✔
3055
   }
3056
}
3057

3058
static vcode_stamp_t vstamp_new(const vstamp_t *s)
774,043✔
3059
{
3060
   assert(active_unit != NULL);
774,043✔
3061

3062
   for (int i = 0; i < active_unit->stamps.count; i++) {
7,612,835✔
3063
      vstamp_t *cmp = &(active_unit->stamps.items[i]);
7,275,894✔
3064
      if (cmp->kind == s->kind && memcmp(&cmp->u, &s->u, sizeof(s->u)) == 0)
7,275,894✔
3065
         return MAKE_HANDLE(active_unit->depth, i);
437,102✔
3066
   }
3067

3068
   vstamp_t *new = vstamp_array_alloc(&(active_unit->stamps));
336,941✔
3069
   *new = *s;
336,941✔
3070

3071
   return MAKE_HANDLE(active_unit->depth, active_unit->stamps.count - 1);
336,941✔
3072
}
3073

3074
vcode_stamp_t vstamp_int(int64_t low, int64_t high)
731,630✔
3075
{
3076
   const vstamp_t s = {
731,630✔
3077
      .kind = VCODE_STAMP_INT,
3078
      .u = { .intg = { .low = low, .high = high } },
3079
   };
3080
   return vstamp_new(&s);
731,630✔
3081
}
3082

3083
vcode_stamp_t vstamp_real(double low, double high)
42,413✔
3084
{
3085
   const vstamp_t s = {
42,413✔
3086
      .kind = VCODE_STAMP_REAL,
3087
      .u = { .real = { .low = low, .high = high } },
3088
   };
3089
   return vstamp_new(&s);
42,413✔
3090
}
3091

3092
vcode_stamp_t vstamp_char(void)
1,509✔
3093
{
3094
   return vstamp_int(0, 255);
1,509✔
3095
}
3096

3097
int vcode_count_params(void)
13,166✔
3098
{
3099
   assert(active_unit != NULL);
13,166✔
3100
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
13,166✔
3101
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3102
          || active_unit->kind == VCODE_UNIT_PROPERTY
3103
          || active_unit->kind == VCODE_UNIT_PROTECTED);
3104

3105
   return active_unit->params.count;
13,166✔
3106
}
3107

3108
vcode_type_t vcode_param_type(int param)
31,368✔
3109
{
3110
   assert(active_unit != NULL);
31,368✔
3111
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,368✔
3112
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3113
          || active_unit->kind == VCODE_UNIT_PROPERTY
3114
          || active_unit->kind == VCODE_UNIT_PROTECTED);
3115
   assert(param < active_unit->params.count);
31,368✔
3116

3117
   return active_unit->params.items[param].type;
31,368✔
3118
}
3119

3120
ident_t vcode_param_name(int param)
31,368✔
3121
{
3122
   assert(active_unit != NULL);
31,368✔
3123
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,368✔
3124
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3125
          || active_unit->kind == VCODE_UNIT_PROPERTY
3126
          || active_unit->kind == VCODE_UNIT_PROTECTED);
3127
   assert(param < active_unit->params.count);
31,368✔
3128

3129
   return active_unit->params.items[param].name;
31,368✔
3130
}
3131

3132
vcode_reg_t vcode_param_reg(int param)
31,368✔
3133
{
3134
   assert(active_unit != NULL);
31,368✔
3135
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,368✔
3136
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3137
          || active_unit->kind == VCODE_UNIT_PROPERTY
3138
          || active_unit->kind == VCODE_UNIT_PROTECTED);
3139
   assert(param < active_unit->params.count);
31,368✔
3140

3141
   return active_unit->params.items[param].reg;
31,368✔
3142
}
3143

3144
vcode_block_t emit_block(void)
137,294✔
3145
{
3146
   assert(active_unit != NULL);
137,294✔
3147

3148
   vcode_block_t bnum = active_unit->blocks.count;
137,294✔
3149

3150
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
137,294✔
3151
   memset(bptr, '\0', sizeof(block_t));
137,294✔
3152

3153
   if (active_block != VCODE_INVALID_BLOCK)
137,294✔
3154
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
86,623✔
3155
   else
3156
      bptr->last_loc = LOC_INVALID;
50,671✔
3157

3158
   return bnum;
137,294✔
3159
}
3160

3161
void vcode_select_unit(vcode_unit_t unit)
173,688✔
3162
{
3163
   active_unit  = unit;
173,688✔
3164
   active_block = VCODE_INVALID_BLOCK;
173,688✔
3165
}
173,688✔
3166

3167
void vcode_select_block(vcode_block_t block)
298,593✔
3168
{
3169
   assert(active_unit != NULL);
298,593✔
3170
   active_block = block;
298,593✔
3171
}
298,593✔
3172

3173
vcode_block_t vcode_active_block(void)
741✔
3174
{
3175
   assert(active_unit != NULL);
741✔
3176
   assert(active_block != -1);
741✔
3177
   return active_block;
741✔
3178
}
3179

3180
const loc_t *vcode_last_loc(void)
1,193,831✔
3181
{
3182
   return &(vcode_block_data()->last_loc);
1,193,831✔
3183
}
3184

3185
vcode_unit_t vcode_active_unit(void)
742✔
3186
{
3187
   assert(active_unit != NULL);
742✔
3188
   return active_unit;
742✔
3189
}
3190

3191
ident_t vcode_unit_name(vcode_unit_t vu)
147,246✔
3192
{
3193
   assert(vu != NULL);
147,246✔
3194
   return vu->name;
147,246✔
3195
}
3196

3197
bool vcode_unit_has_undefined(vcode_unit_t vu)
11,170✔
3198
{
3199
   assert(vu != NULL);
11,170✔
3200
   return !!(vu->flags & UNIT_UNDEFINED);
11,170✔
3201
}
3202

UNCOV
3203
int vcode_unit_depth(vcode_unit_t vu)
×
3204
{
UNCOV
3205
   assert(vu != NULL);
×
UNCOV
3206
   return vu->depth;
×
3207
}
3208

3209
void vcode_set_result(vcode_type_t type)
21,194✔
3210
{
3211
   assert(active_unit != NULL);
21,194✔
3212
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
21,194✔
3213
          || active_unit->kind == VCODE_UNIT_THUNK);
3214

3215
   active_unit->result = type;
21,194✔
3216
}
21,194✔
3217

3218
vcode_type_t vcode_unit_result(vcode_unit_t vu)
23,292✔
3219
{
3220
   assert(vu != NULL);
23,292✔
3221
   assert(vu->kind == VCODE_UNIT_FUNCTION || vu->kind == VCODE_UNIT_THUNK);
23,292✔
3222
   return vu->result;
23,292✔
3223
}
3224

3225
vunit_kind_t vcode_unit_kind(vcode_unit_t vu)
131,413✔
3226
{
3227
   assert(vu != NULL);
131,413✔
3228
   return vu->kind;
131,413✔
3229
}
3230

3231
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
79,228✔
3232
{
3233
   assert(vu != NULL);
79,228✔
3234
   return vu->context;
79,228✔
3235
}
3236

3237
object_t *vcode_unit_object(vcode_unit_t vu)
78,465✔
3238
{
3239
   assert(vu != NULL);
78,465✔
3240
   return vu->object;
78,465✔
3241
}
3242

3243
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
61,853✔
3244
{
3245
   int hops = 0;
61,853✔
3246
   for (; (unit = unit->context); hops++)
151,931✔
3247
      ;
3248
   return hops;
61,853✔
3249
}
3250

3251
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
27,399✔
3252
{
3253
   assert(context->kind != VCODE_UNIT_THUNK);
27,399✔
3254

3255
   child->next = NULL;
27,399✔
3256
   if (context->children == NULL)
27,399✔
3257
      context->children = child;
12,260✔
3258
   else {
3259
      vcode_unit_t it;
3260
      for (it = context->children; it->next != NULL; it = it->next)
70,131✔
3261
         ;
3262
      it->next = child;
15,139✔
3263
   }
3264
}
27,399✔
3265

3266
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
12,171✔
3267
{
3268
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
12,171✔
3269
   vu->kind     = VCODE_UNIT_FUNCTION;
12,171✔
3270
   vu->name     = name;
12,171✔
3271
   vu->context  = context;
12,171✔
3272
   vu->result   = VCODE_INVALID_TYPE;
12,171✔
3273
   vu->depth    = vcode_unit_calc_depth(vu);
12,171✔
3274
   vu->object   = obj;
12,171✔
3275

3276
   vcode_add_child(context, vu);
12,171✔
3277

3278
   vcode_select_unit(vu);
12,171✔
3279
   vcode_select_block(emit_block());
12,171✔
3280
   emit_debug_info(&(obj->loc));
12,171✔
3281

3282
   return vu;
12,171✔
3283
}
3284

3285
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
215✔
3286
{
3287
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
215✔
3288
   vu->kind     = VCODE_UNIT_PROCEDURE;
215✔
3289
   vu->name     = name;
215✔
3290
   vu->context  = context;
215✔
3291
   vu->result   = VCODE_INVALID_TYPE;
215✔
3292
   vu->depth    = vcode_unit_calc_depth(vu);
215✔
3293
   vu->object   = obj;
215✔
3294

3295
   vcode_add_child(context, vu);
215✔
3296

3297
   vcode_select_unit(vu);
215✔
3298
   vcode_select_block(emit_block());
215✔
3299
   emit_debug_info(&(obj->loc));
215✔
3300

3301
   return vu;
215✔
3302
}
3303

3304
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
7,482✔
3305
{
3306
   assert(context->kind == VCODE_UNIT_INSTANCE);
7,482✔
3307

3308
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
7,482✔
3309
   vu->kind     = VCODE_UNIT_PROCESS;
7,482✔
3310
   vu->name     = name;
7,482✔
3311
   vu->context  = context;
7,482✔
3312
   vu->depth    = vcode_unit_calc_depth(vu);
7,482✔
3313
   vu->result   = VCODE_INVALID_TYPE;
7,482✔
3314
   vu->object   = obj;
7,482✔
3315

3316
   vcode_add_child(context, vu);
7,482✔
3317

3318
   vcode_select_unit(vu);
7,482✔
3319
   vcode_select_block(emit_block());
7,482✔
3320
   emit_debug_info(&(obj->loc));
7,482✔
3321

3322
   return vu;
7,482✔
3323
}
3324

3325
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
10,076✔
3326
{
3327
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
10,076✔
3328

3329
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
10,076✔
3330
   vu->kind     = VCODE_UNIT_INSTANCE;
10,076✔
3331
   vu->name     = name;
10,076✔
3332
   vu->context  = context;
10,076✔
3333
   vu->depth    = vcode_unit_calc_depth(vu);
10,076✔
3334
   vu->result   = VCODE_INVALID_TYPE;
10,076✔
3335
   vu->object   = obj;
10,076✔
3336

3337
   if (context != NULL)
10,076✔
3338
      vcode_add_child(context, vu);
6,276✔
3339

3340
   vcode_select_unit(vu);
10,076✔
3341
   vcode_select_block(emit_block());
10,076✔
3342
   emit_debug_info(&(obj->loc));
10,076✔
3343

3344
   return vu;
10,076✔
3345
}
3346

3347
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
8,765✔
3348
{
3349
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
8,765✔
3350
   vu->kind     = VCODE_UNIT_PACKAGE;
8,765✔
3351
   vu->name     = name;
8,765✔
3352
   vu->context  = context;
8,765✔
3353
   vu->depth    = vcode_unit_calc_depth(vu);
8,765✔
3354
   vu->result   = VCODE_INVALID_TYPE;
8,765✔
3355
   vu->object   = obj;
8,765✔
3356

3357
   if (context != NULL)
8,765✔
3358
      vcode_add_child(context, vu);
189✔
3359

3360
   vcode_select_unit(vu);
8,765✔
3361
   vcode_select_block(emit_block());
8,765✔
3362
   emit_debug_info(&(obj->loc));
8,765✔
3363

3364
   return vu;
8,765✔
3365
}
3366

3367
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
540✔
3368
{
3369
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
540✔
3370
   vu->kind     = VCODE_UNIT_PROTECTED;
540✔
3371
   vu->name     = name;
540✔
3372
   vu->context  = context;
540✔
3373
   vu->depth    = vcode_unit_calc_depth(vu);
540✔
3374
   vu->result   = VCODE_INVALID_TYPE;
540✔
3375
   vu->object   = obj;
540✔
3376

3377
   if (context != NULL)
540✔
3378
      vcode_add_child(context, vu);
540✔
3379

3380
   vcode_select_unit(vu);
540✔
3381
   vcode_select_block(emit_block());
540✔
3382
   emit_debug_info(&(obj->loc));
540✔
3383

3384
   return vu;
540✔
3385
}
3386

3387
vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context)
240✔
3388
{
3389
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
240✔
3390
   vu->kind     = VCODE_UNIT_PROPERTY;
240✔
3391
   vu->name     = name;
240✔
3392
   vu->context  = context;
240✔
3393
   vu->depth    = vcode_unit_calc_depth(vu);
240✔
3394
   vu->result   = VCODE_INVALID_TYPE;
240✔
3395
   vu->object   = obj;
240✔
3396

3397
   if (context != NULL)
240✔
3398
      vcode_add_child(context, vu);
240✔
3399

3400
   vcode_select_unit(vu);
240✔
3401
   vcode_select_block(emit_block());
240✔
3402
   emit_debug_info(&(obj->loc));
240✔
3403

3404
   return vu;
240✔
3405
}
3406

3407
vcode_unit_t emit_thunk(ident_t name, object_t *obj, vcode_unit_t context)
11,182✔
3408
{
3409
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
11,182✔
3410
   vu->kind     = VCODE_UNIT_THUNK;
11,182✔
3411
   vu->name     = name;
11,182✔
3412
   vu->context  = context;
11,182✔
3413
   vu->depth    = vcode_unit_calc_depth(vu);
11,182✔
3414
   vu->result   = VCODE_INVALID_TYPE;
11,182✔
3415
   vu->depth    = vcode_unit_calc_depth(vu);
11,182✔
3416
   vu->object   = obj;
11,182✔
3417

3418
   if (context != NULL)
11,182✔
3419
      vcode_add_child(context, vu);
286✔
3420

3421
   vcode_select_unit(vu);
11,182✔
3422
   vcode_select_block(emit_block());
11,182✔
3423

3424
   return vu;
11,182✔
3425
}
3426

3427
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
14,648✔
3428
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3429
                 vcode_reg_t hint_right)
3430
{
3431
   int64_t value_const;
14,648✔
3432
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
14,648✔
3433
      emit_comment("Always true assertion on r%d", value);
30✔
3434
      return;
30✔
3435
   }
3436

3437
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
14,618✔
3438
   vcode_add_arg(op, value);
14,618✔
3439
   vcode_add_arg(op, severity);
14,618✔
3440
   vcode_add_arg(op, message);
14,618✔
3441
   vcode_add_arg(op, length);
14,618✔
3442
   vcode_add_arg(op, locus);
14,618✔
3443

3444
   if (hint_left != VCODE_INVALID_REG) {
14,618✔
3445
      vcode_add_arg(op, hint_left);
6,080✔
3446
      vcode_add_arg(op, hint_right);
6,080✔
3447

3448
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
6,080✔
3449
                   "left hint must be scalar");
3450
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
6,080✔
3451
                   "right hint must be scalar");
3452
   }
3453

3454
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
14,618✔
3455
                "value parameter to assert is not bool");
3456
   VCODE_ASSERT(message == VCODE_INVALID_REG
14,618✔
3457
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3458
                "message parameter to assert is not a pointer");
3459
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
14,618✔
3460
                "value parameter to assert is not bool");
3461
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
14,618✔
3462
                "locus argument to report must be a debug locus");
3463
}
3464

3465
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,101✔
3466
                 vcode_reg_t locus)
3467
{
3468
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,101✔
3469
   vcode_add_arg(op, severity);
2,101✔
3470
   vcode_add_arg(op, message);
2,101✔
3471
   vcode_add_arg(op, length);
2,101✔
3472
   vcode_add_arg(op, locus);
2,101✔
3473

3474
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,101✔
3475
                "message parameter to report is not a pointer");
3476
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,101✔
3477
                "message parameter to report is not a character pointer");
3478
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,101✔
3479
                "locus argument to report must be a debug locus");
3480
}
2,101✔
3481

3482
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
34,516✔
3483
{
3484
   if (lhs == rhs) {
34,516✔
3485
      if (cmp == VCODE_CMP_EQ)
400✔
3486
         return emit_const(vtype_bool(), 1);
241✔
3487
      else if (cmp == VCODE_CMP_NEQ)
159✔
UNCOV
3488
         return emit_const(vtype_bool(), 0);
×
3489
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
159✔
UNCOV
3490
         return emit_const(vtype_bool(), 1);
×
3491
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
159✔
3492
         return emit_const(vtype_bool(), 0);
159✔
3493
   }
3494

3495
   int64_t lconst, rconst;
34,116✔
3496
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
34,116✔
3497
      switch (cmp) {
328✔
3498
      case VCODE_CMP_EQ:
306✔
3499
         return emit_const(vtype_bool(), lconst == rconst);
306✔
3500
      case VCODE_CMP_NEQ:
3✔
3501
         return emit_const(vtype_bool(), lconst != rconst);
3✔
3502
      case VCODE_CMP_LT:
9✔
3503
         return emit_const(vtype_bool(), lconst < rconst);
9✔
3504
      case VCODE_CMP_GT:
10✔
3505
         return emit_const(vtype_bool(), lconst > rconst);
10✔
UNCOV
3506
      case VCODE_CMP_LEQ:
×
UNCOV
3507
         return emit_const(vtype_bool(), lconst <= rconst);
×
UNCOV
3508
      case VCODE_CMP_GEQ:
×
UNCOV
3509
         return emit_const(vtype_bool(), lconst >= rconst);
×
UNCOV
3510
      default:
×
3511
         fatal_trace("cannot fold comparison %d", cmp);
3512
      }
3513
   }
3514

3515
   // Reuse any previous operation in this block with the same arguments
3516
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
664,224✔
3517
      if (other->args.count == 2 && other->args.items[0] == lhs
24,501✔
3518
          && other->args.items[1] == rhs && other->cmp == cmp)
2,300✔
3519
         return other->result;
195✔
3520
   }
3521

3522
   op_t *op = vcode_add_op(VCODE_OP_CMP);
33,593✔
3523
   vcode_add_arg(op, lhs);
33,593✔
3524
   vcode_add_arg(op, rhs);
33,593✔
3525
   op->cmp    = cmp;
33,593✔
3526
   op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP);
33,593✔
3527

3528
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
33,593✔
3529
                "arguments to cmp are not the same type");
3530

3531
   return op->result;
33,593✔
3532
}
3533

3534
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_stamp_t stamp,
34,339✔
3535
                       const vcode_reg_t *args, int nargs)
3536
{
3537
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
34,339✔
3538
   o->func = func;
34,339✔
3539
   o->type = type;
34,339✔
3540
   for (int i = 0; i < nargs; i++)
120,883✔
3541
      vcode_add_arg(o, args[i]);
86,544✔
3542

3543
   for (int i = 0; i < nargs; i++)
120,883✔
3544
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
86,544✔
3545
                   "invalid argument to function");
3546

3547
   if (type == VCODE_INVALID_TYPE)
34,339✔
3548
      return (o->result = VCODE_INVALID_REG);
5,579✔
3549
   else
3550
      return (o->result = vcode_add_reg(type, stamp));
28,760✔
3551
}
3552

3553
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
847✔
3554
                vcode_block_t resume_bb)
3555
{
3556
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
847✔
3557
   o->func = func;
847✔
3558
   for (int i = 0; i < nargs; i++)
2,852✔
3559
      vcode_add_arg(o, args[i]);
2,005✔
3560

3561
   vcode_block_array_add(&(o->targets), resume_bb);
847✔
3562

3563
   for (int i = 0; i < nargs; i++)
2,852✔
3564
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,005✔
3565
                   "invalid argument to procedure");
3566

3567
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
847✔
3568
                "first argument to VHDL procedure must be context pointer");
3569
}
847✔
3570

3571
vcode_reg_t emit_alloc(vcode_type_t type, vcode_stamp_t stamp,
7,255✔
3572
                       vcode_reg_t count)
3573
{
3574
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
7,255✔
3575
   op->type = type;
7,255✔
3576
   vcode_add_arg(op, count);
7,255✔
3577

3578
   const vtype_kind_t tkind = vtype_kind(type);
7,255✔
3579
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
7,255✔
3580
                "alloca element type cannot be array");
3581
   VCODE_ASSERT(count != VCODE_INVALID_REG,
7,255✔
3582
                "alloca must have valid count argument");
3583

3584
   return (op->result = vcode_add_reg(vtype_pointer(type), stamp));
7,255✔
3585
}
3586

3587
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
1,451,840✔
3588
{
3589
   // Reuse any previous constant in this block with the same type and value
3590
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
33,207,694✔
3591
      if (other->value == value && vtype_eq(type, other->type))
11,727,416✔
3592
         return other->result;
1,003,392✔
3593
   }
3594

3595
   op_t *op = vcode_add_op(VCODE_OP_CONST);
448,448✔
3596
   op->value  = value;
448,448✔
3597
   op->type   = type;
448,448✔
3598
   op->result = vcode_add_reg(type, vstamp_int(value, value));
448,448✔
3599

3600
   vtype_kind_t type_kind = vtype_kind(type);
448,448✔
3601
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
448,448✔
3602
                "constant must have integer or offset type");
3603

3604
   return op->result;
3605
}
3606

3607
vcode_reg_t emit_const_real(vcode_type_t type, double value)
66,789✔
3608
{
3609
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
1,958,770✔
3610
      if (other->real == value && other->type == type)
907,978✔
3611
         return other->result;
25,345✔
3612
   }
3613

3614
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
41,444✔
3615
   op->real   = value;
41,444✔
3616
   op->type   = type;
41,444✔
3617
   op->result = vcode_add_reg(op->type, vstamp_real(value, value));
41,444✔
3618

3619
   return op->result;
41,444✔
3620
}
3621

3622
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
37,536✔
3623
{
3624
   vtype_kind_t kind = vtype_kind(type);
37,536✔
3625

3626
   // Reuse any previous operation in this block with the same arguments
3627
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,929,065✔
3628
      if (other->args.count != num)
151,709✔
3629
         continue;
90,445✔
3630
      else if (!vtype_eq(vcode_reg_type(other->result), type))
61,264✔
3631
         continue;
2,318✔
3632

3633
      bool match = true;
3634
      for (int i = 0; match && i < num; i++) {
423,224✔
3635
         if (other->args.items[i] != values[i])
364,278✔
3636
            match = false;
51,863✔
3637
      }
3638

3639
      if (match) return other->result;
58,946✔
3640
   }
3641

3642
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
30,453✔
3643
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
30,453✔
3644

3645
   for (int i = 0; i < num; i++)
1,683,643✔
3646
      vcode_add_arg(op, values[i]);
1,653,190✔
3647

3648
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
30,453✔
3649
                "constant array must have constrained array type");
3650
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
30,453✔
3651
                vtype_size(type), num);
3652

3653
#ifdef DEBUG
3654
   vcode_type_t elem = vtype_elem(type);
30,453✔
3655
   for (int i = 0; i < num; i++) {
1,683,643✔
3656
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,653,190✔
3657
                   "wrong element type for item %d", i);
3658
      vcode_assert_const(values[i], "array");
1,653,190✔
3659
   }
3660
#endif
3661

3662
   return op->result;
30,453✔
3663
}
3664

3665
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
440✔
3666
{
3667
   // Reuse any previous operation in this block with the same arguments
3668
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
8,047✔
3669
      if (other->args.items[0] == value && other->value == rep)
427✔
3670
         return other->result;
168✔
3671
   }
3672

3673
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
272✔
3674
   op->value = rep;
272✔
3675
   vcode_add_arg(op, value);
272✔
3676

3677
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
272✔
3678
                "constant array must have constrained array type");
3679
   VCODE_ASSERT(rep >= 0, "repeat count must be non-negative");
272✔
3680

3681
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
272✔
3682

3683
   return (op->result = vcode_add_reg(type, vcode_reg_data(value)->stamp));
272✔
3684
}
3685

3686
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
2,495✔
3687
{
3688
   // Reuse any previous constant in this block with the same type and value
3689
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
38,488✔
3690
      if (other->args.count == num && vtype_eq(type, other->type)) {
1,474✔
3691
         bool same_regs = true;
3692
         for (int i = 0; same_regs && i < num; i++)
2,522✔
3693
            same_regs = other->args.items[i] == values[i];
1,472✔
3694

3695
         if (same_regs)
1,050✔
3696
            return other->result;
187✔
3697
      }
3698
   }
3699

3700
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
2,308✔
3701
   op->type   = type;
2,308✔
3702
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
2,308✔
3703

3704
   for (int i = 0; i < num; i++)
8,253✔
3705
      vcode_add_arg(op, values[i]);
5,945✔
3706

3707
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
2,308✔
3708
                "constant record must have record type");
3709

3710
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
2,308✔
3711
                vtype_fields(type), num);
3712

3713
#ifdef DEBUG
3714
   for (int i = 0; i < num; i++) {
8,253✔
3715
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
5,945✔
3716
                   "wrong type for field %d", i);
3717
      vcode_assert_const(values[i], "record");
5,945✔
3718
   }
3719
#endif
3720

3721
   return op->result;
2,308✔
3722
}
3723

3724
vcode_reg_t emit_address_of(vcode_reg_t value)
39,114✔
3725
{
3726
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
2,003,673✔
3727
      if (other->args.items[0] == value)
152,721✔
3728
         return other->result;
7,084✔
3729
   }
3730

3731
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
32,030✔
3732
   vcode_add_arg(op, value);
32,030✔
3733

3734
   vcode_type_t vtype = vcode_reg_type(value);
32,030✔
3735

3736
   VCODE_ASSERT(vtype_is_composite(vtype),
32,030✔
3737
                "address of argument must be record or array");
3738

3739
   if (vtype_kind(vtype) == VCODE_TYPE_CARRAY) {
32,030✔
3740
      vcode_type_t elem = vtype_elem(vtype);
30,238✔
3741
      vcode_stamp_t stamp = vcode_reg_stamp(value);
30,238✔
3742
      return (op->result = vcode_add_reg(vtype_pointer(elem), stamp));
30,238✔
3743
   }
3744
   else {
3745
      vcode_stamp_t stamp = VCODE_INVALID_STAMP;
1,792✔
3746
      return (op->result = vcode_add_reg(vtype_pointer(vtype), stamp));
1,792✔
3747
   }
3748
}
3749

3750
void emit_wait(vcode_block_t target)
12,733✔
3751
{
3752
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
12,733✔
3753
   vcode_add_target(op, target);
12,733✔
3754
}
12,733✔
3755

3756
void emit_jump(vcode_block_t target)
36,007✔
3757
{
3758
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
36,007✔
3759
   vcode_add_target(op, target);
36,007✔
3760

3761
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
36,007✔
3762
}
36,007✔
3763

3764
vcode_var_t emit_var(vcode_type_t type, vcode_stamp_t stamp, ident_t name,
71,906✔
3765
                     vcode_var_flags_t flags)
3766
{
3767
   assert(active_unit != NULL);
71,906✔
3768

3769
   vcode_var_t var = active_unit->vars.count;
71,906✔
3770
   var_t *v = var_array_alloc(&(active_unit->vars));
71,906✔
3771
   memset(v, '\0', sizeof(var_t));
71,906✔
3772
   v->type  = type;
71,906✔
3773
   v->stamp = stamp;
71,906✔
3774
   v->name  = name;
71,906✔
3775
   v->flags = flags;
71,906✔
3776

3777
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
71,906✔
3778

3779
   return var;
71,906✔
3780
}
3781

3782
vcode_reg_t emit_param(vcode_type_t type, vcode_stamp_t stamp, ident_t name)
31,654✔
3783
{
3784
   assert(active_unit != NULL);
31,654✔
3785

3786
   param_t *p = param_array_alloc(&(active_unit->params));
31,654✔
3787
   memset(p, '\0', sizeof(param_t));
31,654✔
3788
   p->type  = type;
31,654✔
3789
   p->stamp = stamp;
31,654✔
3790
   p->name  = name;
31,654✔
3791
   p->reg   = vcode_add_reg(type, stamp);
31,654✔
3792

3793
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
31,654✔
3794

3795
   return p->reg;
31,654✔
3796
}
3797

3798
vcode_reg_t emit_load(vcode_var_t var)
60,578✔
3799
{
3800
   // Try scanning backwards through the block for another load or store to
3801
   // this variable
3802
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
60,578✔
3803
   vcode_reg_t fold = VCODE_INVALID_REG;
60,578✔
3804
   VCODE_FOR_EACH_OP(other) {
868,947✔
3805
      switch (state) {
824,757✔
3806
      case EAGER:
334,066✔
3807
         if (other->kind == VCODE_OP_LOAD && other->address == var)
334,066✔
3808
            return other->result;
3,854✔
3809
         else if (other->kind == VCODE_OP_STORE && other->address == var)
330,212✔
3810
            return other->args.items[0];
12,534✔
3811
         else if (other->kind == VCODE_OP_FCALL
317,678✔
3812
                  || other->kind == VCODE_OP_PCALL
317,678✔
3813
                  || other->kind == VCODE_OP_FILE_READ
3814
                  || other->kind == VCODE_OP_FILE_OPEN
3815
                  || other->kind == VCODE_OP_STORE_INDIRECT
3816
                  || other->kind == VCODE_OP_DEALLOCATE)
3817
            state = CONSERVATIVE;   // May write to variable
9,816✔
3818
         break;
3819

3820
      case CONSERVATIVE:
458,964✔
3821
         if (other->kind == VCODE_OP_LOAD && other->address == var
458,964✔
3822
             && fold == VCODE_INVALID_REG)
4,520✔
3823
            fold = other->result;
3,623✔
3824
         else if (other->kind == VCODE_OP_STORE && other->address == var
455,341✔
3825
                  && fold == VCODE_INVALID_REG)
2,417✔
3826
            fold = other->args.items[0];
2,275✔
3827
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
453,066✔
3828
            state = UNSAFE;
3829
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
451,648✔
3830
            state = UNSAFE;   // Nested call captures variables
133✔
3831
         break;
3832

3833
      case UNSAFE:
3834
         break;
3835
      }
3836
   }
3837

3838
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
44,190✔
3839
      return fold;
3840

3841
   var_t *v = vcode_var_data(var);
38,686✔
3842

3843
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
38,686✔
3844
   op->address = var;
38,686✔
3845
   op->result  = vcode_add_reg(v->type, v->stamp);
38,686✔
3846

3847
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
38,686✔
3848

3849
   return op->result;
3850
}
3851

3852
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
94,431✔
3853
{
3854
   VCODE_FOR_EACH_OP(other) {
1,116,790✔
3855
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,053,429✔
3856
          && other->args.items[0] == reg) {
152,952✔
3857
         return other->result;
10,567✔
3858
      }
3859
      else if (other->kind == VCODE_OP_FCALL
1,042,862✔
3860
               || other->kind == VCODE_OP_PCALL
1,042,862✔
3861
               || other->kind == VCODE_OP_STORE
3862
               || other->kind == VCODE_OP_STORE_INDIRECT
3863
               || other->kind == VCODE_OP_MEMSET
3864
               || other->kind == VCODE_OP_COPY
3865
               || other->kind == VCODE_OP_FILE_READ)
3866
         break;   // May write to this pointer
3867
   }
3868

3869
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
83,864✔
3870
   vcode_add_arg(op, reg);
83,864✔
3871

3872
   vcode_type_t rtype = vcode_reg_type(reg);
83,864✔
3873

3874
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
83,864✔
3875
                "load indirect with non-pointer argument");
3876

3877
   vcode_type_t deref = vtype_pointed(rtype);
83,864✔
3878
   op->result = vcode_add_reg(deref, vcode_reg_stamp(reg));
83,864✔
3879

3880
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
83,864✔
3881

3882
   return op->result;
3883
}
3884

3885
void emit_store(vcode_reg_t reg, vcode_var_t var)
76,580✔
3886
{
3887
   // Any previous store to this variable in this block is dead
3888
   VCODE_FOR_EACH_OP(other) {
1,612,570✔
3889
      if (other->kind == VCODE_OP_STORE && other->address == var) {
1,550,454✔
3890
         other->kind = VCODE_OP_COMMENT;
290✔
3891
         other->comment =
580✔
3892
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
290✔
3893
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
290✔
3894
      }
3895
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
1,550,164✔
3896
         break;   // Needs to get variable for display
3897
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
1,543,874✔
3898
               && other->address == var)
37,610✔
3899
         break;   // Previous value may be used
3900
   }
3901

3902
   var_t *v = vcode_var_data(var);
76,580✔
3903
   reg_t *r = vcode_reg_data(reg);
76,580✔
3904

3905
   op_t *op = vcode_add_op(VCODE_OP_STORE);
76,580✔
3906
   vcode_add_arg(op, reg);
76,580✔
3907
   op->address = var;
76,580✔
3908

3909
   VCODE_ASSERT(vtype_eq(v->type, r->type),
76,580✔
3910
                "variable and stored value do not have same type");
3911
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
76,580✔
3912
}
76,580✔
3913

3914
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
14,998✔
3915
{
3916
   reg_t *p = vcode_reg_data(ptr);
14,998✔
3917
   reg_t *r = vcode_reg_data(reg);
14,998✔
3918

3919
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
14,998✔
3920
   vcode_add_arg(op, reg);
14,998✔
3921
   vcode_add_arg(op, ptr);
14,998✔
3922

3923
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
14,998✔
3924
                "store indirect target is not a pointer");
3925
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
14,998✔
3926
                "pointer and stored value do not have same type");
3927
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
14,998✔
3928
}
14,998✔
3929

3930
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
67,112✔
3931
                              vcode_reg_t locus)
3932
{
3933
   // Reuse any previous operation in this block with the same arguments
3934
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,572,266✔
3935
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
77,661✔
3936
         return other->result;
5,928✔
3937
   }
3938

3939
   op_t *op = vcode_add_op(kind);
61,184✔
3940
   vcode_add_arg(op, lhs);
61,184✔
3941
   vcode_add_arg(op, rhs);
61,184✔
3942
   if (locus != VCODE_INVALID_REG)
61,184✔
3943
      vcode_add_arg(op, locus);
7,850✔
3944

3945
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
61,184✔
3946

3947
   vcode_type_t lhs_type = vcode_reg_type(lhs);
61,184✔
3948
   vcode_type_t rhs_type = vcode_reg_type(rhs);
61,184✔
3949

3950
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
61,184✔
3951
                "arguments to %s are not the same type", vcode_op_string(kind));
3952

3953
   return op->result;
61,184✔
3954
}
3955

3956
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
48,099✔
3957
                               vcode_reg_t locus)
3958
{
3959
   int64_t lconst, rconst;
48,099✔
3960
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
48,099✔
3961
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
48,099✔
3962
   if (l_is_const && r_is_const)
48,099✔
3963
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
22,255✔
3964
   else if (r_is_const && rconst == 1)
25,844✔
3965
      return lhs;
3966
   else if (l_is_const && lconst == 1)
4,790✔
3967
      return rhs;
3968
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
4,288✔
3969
      return emit_const(vcode_reg_type(lhs), 0);
54✔
3970

3971
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
4,234✔
3972

3973
   double rl_low, rl_high, rr_low, rr_high;
4,234✔
3974
   int64_t l_low, l_high, r_low, r_high;
4,234✔
3975

3976
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
4,234✔
3977
       && vcode_reg_bounds(rhs, &r_low, &r_high)) {
3,678✔
3978
      const int64_t ll = smul64(l_low, r_low);
3,678✔
3979
      const int64_t lh = smul64(l_low, r_high);
3,678✔
3980
      const int64_t hl = smul64(l_high, r_low);
3,678✔
3981
      const int64_t hh = smul64(l_high, r_high);
3,678✔
3982

3983
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
3,678✔
3984
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
3,678✔
3985

3986
      if (min > INT64_MIN && max < INT64_MAX) {
3,678✔
3987
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
2,033✔
3988
         if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
2,033✔
3989
            op = VCODE_OP_MUL;   // Cannot overflow
611✔
3990
            locus = VCODE_INVALID_REG;
611✔
3991
         }
3992
      }
3993

3994
      vstamp = vstamp_int(min, max);
3,678✔
3995
   }
3996
   else if (vcode_reg_bounds_real(lhs, &rl_low, &rl_high)
556✔
3997
            && vcode_reg_bounds_real(rhs, &rr_low, &rr_high)) {
556✔
3998
      const double ll = rl_low * rr_low;
556✔
3999
      const double lh = rl_low * rr_high;
556✔
4000
      const double hl = rl_high * rr_low;
556✔
4001
      const double hh = rl_high * rr_high;
556✔
4002

4003
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,301✔
4004
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,387✔
4005

4006
      vstamp = vstamp_real(min, max);
556✔
4007
   }
4008

4009
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
4,234✔
4010

4011
   if (vstamp != VCODE_INVALID_TYPE)
4,234✔
4012
      vcode_reg_data(reg)->stamp = vstamp;
4,234✔
4013

4014
   return reg;
4015
}
4016

4017
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
45,283✔
4018
{
4019
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
45,283✔
4020
}
4021

4022
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
2,816✔
4023
{
4024
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
2,816✔
4025

4026
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
2,816✔
4027
                "trapping add may only be used with integer types");
4028

4029
   return result;
2,816✔
4030
}
4031

4032
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
1,762✔
4033
{
4034
   int64_t lconst, rconst;
1,762✔
4035
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
1,762✔
4036
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
1,762✔
4037
   if (l_is_const && r_is_const && rconst != 0)
1,762✔
4038
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
30✔
4039
   else if (r_is_const && rconst == 1)
1,732✔
4040
      return lhs;
4041

4042
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
1,729✔
4043

4044
   int64_t l_low, l_high;
1,729✔
4045
   if (vcode_reg_bounds(lhs, &l_low, &l_high)) {
1,729✔
4046
      if (r_is_const && rconst != 0) {
1,412✔
4047
         reg_t *rr = vcode_reg_data(reg);
1,339✔
4048
         rr->stamp = vstamp_int(l_low / rconst, l_high / rconst);
1,339✔
4049
      }
4050
   }
4051
   else {
4052
      reg_t *rr = vcode_reg_data(reg);
317✔
4053
      rr->stamp = vstamp_real(-INFINITY, INFINITY);
317✔
4054
   }
4055

4056
   return reg;
4057
}
4058

4059
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
141✔
4060
{
4061
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
141✔
4062
}
4063

4064
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
411✔
4065
{
4066
   int64_t rconst;
411✔
4067
   if (vcode_reg_const(rhs, &rconst)) {
411✔
4068
      if (rconst == 0)
77✔
4069
         return emit_const(vcode_reg_type(lhs), 1);
31✔
4070
      else if (rconst == 1)
46✔
4071
         return lhs;
4072
   }
4073

4074
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
379✔
4075

4076
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
379✔
4077
                "trapping exp may only be used with integer types");
4078

4079
   return result;
4080
}
4081

4082
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
199✔
4083
{
4084
   int64_t lconst, rconst;
199✔
4085
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
199✔
4086
       && lconst > 0 && rconst > 0)
15✔
4087
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
3✔
4088

4089
   int64_t l_low, l_high, r_low, r_high;
196✔
4090
   if (vcode_reg_bounds(lhs, &l_low, &l_high) && l_low >= 0
196✔
4091
       && vcode_reg_bounds(rhs, &r_low, &r_high) && r_low >= 0) {
91✔
4092
      // If both arguments are non-negative then rem is equivalent and
4093
      // cheaper to compute
4094
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
87✔
4095

4096
      reg_t *rr = vcode_reg_data(reg);
87✔
4097
      rr->stamp = vstamp_int(0, MAX(0, r_high - 1));
87✔
4098

4099
      return reg;
87✔
4100
   }
4101
   else
4102
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
109✔
4103
}
4104

4105
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
891✔
4106
{
4107
   int64_t lconst, rconst;
891✔
4108
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
891✔
4109
       && lconst > 0 && rconst > 0)
2✔
UNCOV
4110
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
4111

4112
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
891✔
4113

4114
   int64_t l_low, l_high, r_low, r_high;
891✔
4115
   if (vcode_reg_bounds(lhs, &l_low, &l_high) && l_low >= 0
891✔
4116
       && vcode_reg_bounds(rhs, &r_low, &r_high) && r_low >= 0) {
505✔
4117
      reg_t *rr = vcode_reg_data(reg);
501✔
4118
      rr->stamp = vstamp_int(0, r_high - 1);
501✔
4119
   }
4120

4121
   return reg;
4122
}
4123

4124
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
48,073✔
4125
                               vcode_reg_t locus)
4126
{
4127
   int64_t lconst, rconst;
48,073✔
4128
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
48,073✔
4129
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
48,073✔
4130
   if (l_is_const && r_is_const)
48,073✔
4131
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
12,017✔
4132
   else if (r_is_const && rconst == 0)
36,056✔
4133
      return lhs;
4134
   else if (l_is_const && lconst == 0)
35,928✔
4135
      return rhs;
4136

4137
   int64_t l_low, l_high, r_low, r_high;
19,984✔
4138
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
19,984✔
4139
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
19,984✔
4140
       && vcode_reg_bounds(rhs, &r_low, &r_high))  {
19,660✔
4141

4142
      int64_t rbl = sadd64(l_low, r_low);
19,660✔
4143
      int64_t rbh = sadd64(l_high, r_high);
19,660✔
4144

4145
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
19,660✔
4146
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
10,520✔
4147
         if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
10,520✔
4148
            op = VCODE_OP_ADD;   // Cannot overflow
1,176✔
4149
            locus = VCODE_INVALID_REG;
1,176✔
4150
         }
4151
      }
4152

4153
      vstamp = vstamp_int(rbl, rbh);
19,660✔
4154
   }
4155

4156
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
19,984✔
4157

4158
   if (vstamp != VCODE_INVALID_STAMP)
19,984✔
4159
      vcode_reg_data(reg)->stamp = vstamp;
19,660✔
4160

4161
   return reg;
4162
}
4163

4164
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
41,762✔
4165
{
4166
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
41,762✔
4167
}
4168

4169
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
6,311✔
4170
{
4171
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
6,311✔
4172

4173
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
6,311✔
4174
                "trapping add may only be used with integer types");
4175

4176
   return result;
6,311✔
4177
}
4178

4179
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
46,175✔
4180
                               vcode_reg_t locus)
4181
{
4182
   int64_t lconst, rconst;
46,175✔
4183
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
46,175✔
4184
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
46,175✔
4185
   if (l_is_const && r_is_const)
46,175✔
4186
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
8,349✔
4187
   else if (r_is_const && rconst == 0)
37,826✔
4188
      return lhs;
4189
   else if (l_is_const && lconst == 0)
33,451✔
4190
      return emit_neg(rhs);
840✔
4191

4192
   int64_t l_low, l_high, r_low, r_high;
32,611✔
4193
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
32,611✔
4194
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
32,611✔
4195
       && vcode_reg_bounds(rhs, &r_low, &r_high))  {
32,316✔
4196

4197
      int64_t rbl = ssub64(l_low, r_high);
32,316✔
4198
      int64_t rbh = ssub64(l_high, r_low);
32,316✔
4199

4200
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
32,316✔
4201
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
29,900✔
4202
         if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
29,900✔
4203
            op = VCODE_OP_SUB;   // Cannot overflow
4,946✔
4204
            locus = VCODE_INVALID_REG;
4,946✔
4205
         }
4206
      }
4207

4208
      vstamp = vstamp_int(rbl, rbh);
32,316✔
4209
   }
4210

4211
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
32,611✔
4212

4213
   if (vstamp != VCODE_INVALID_TYPE)
32,611✔
4214
      vcode_reg_data(reg)->stamp = vstamp;
32,316✔
4215

4216
   return reg;
4217
}
4218

4219
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
39,042✔
4220
{
4221
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
39,042✔
4222
}
4223

4224
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
7,133✔
4225
{
4226
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
7,133✔
4227

4228
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
7,133✔
4229
                "trapping sub may only be used with integer types");
4230

4231
   return result;
7,133✔
4232
}
4233

4234
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
71,081✔
4235
{
4236
   switch (vtype_kind(var->type)) {
71,081✔
4237
   case VCODE_TYPE_CARRAY:
21,716✔
4238
      op->type = vtype_pointer(vtype_elem(var->type));
21,716✔
4239
      op->result = vcode_add_reg(op->type, var->stamp);
21,716✔
4240
      break;
21,716✔
4241

4242
   case VCODE_TYPE_RECORD:
5,818✔
4243
      op->type = vtype_pointer(var->type);
5,818✔
4244
      op->result = vcode_add_reg(op->type, VCODE_INVALID_STAMP);
5,818✔
4245
      break;
5,818✔
4246

4247
   case VCODE_TYPE_INT:
43,547✔
4248
   case VCODE_TYPE_FILE:
4249
   case VCODE_TYPE_ACCESS:
4250
   case VCODE_TYPE_REAL:
4251
   case VCODE_TYPE_UARRAY:
4252
   case VCODE_TYPE_POINTER:
4253
   case VCODE_TYPE_SIGNAL:
4254
   case VCODE_TYPE_CONTEXT:
4255
   case VCODE_TYPE_OFFSET:
4256
   case VCODE_TYPE_TRIGGER:
4257
   case VCODE_TYPE_RESOLUTION:
4258
      op->type = vtype_pointer(var->type);
43,547✔
4259
      op->result = vcode_add_reg(op->type, var->stamp);
43,547✔
4260
      break;
43,547✔
4261

4262
   default:
UNCOV
4263
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4264
                   istr(var->name));
4265
   }
4266
}
71,081✔
4267

4268
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
34,404✔
4269
{
4270
   // Try to find a previous index of this var by this offset
4271
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
1,399,265✔
4272
      if (other->address == var
84,025✔
4273
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
7,292✔
UNCOV
4274
              || (offset != VCODE_INVALID_REG
×
UNCOV
4275
                  && other->args.items[0] == offset)))
×
4276
         return other->result;
7,292✔
4277
   }
4278

4279
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
27,112✔
4280
   op->address = var;
27,112✔
4281

4282
   if (offset != VCODE_INVALID_REG)
27,112✔
UNCOV
4283
      vcode_add_arg(op, offset);
×
4284

4285
   vcode_calculate_var_index_type(op, vcode_var_data(var));
27,112✔
4286

4287
   if (offset != VCODE_INVALID_REG)
27,112✔
UNCOV
4288
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4289
                   "index offset r%d does not have offset type", offset);
4290

4291
   return op->result;
27,112✔
4292
}
4293

4294
vcode_reg_t emit_cast(vcode_type_t type, vcode_stamp_t stamp, vcode_reg_t reg)
243,695✔
4295
{
4296
   if (vtype_eq(vcode_reg_type(reg), type))
243,695✔
4297
      return reg;
243,695✔
4298

4299
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
82,209✔
4300
   vtype_kind_t to   = vtype_kind(type);
82,209✔
4301

4302
   const bool integral =
164,418✔
4303
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
82,209✔
4304
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
82,209✔
4305

4306
   int64_t value;
82,209✔
4307
   if (integral && vcode_reg_const(reg, &value))
82,209✔
4308
      return emit_const(type, value);
12,806✔
4309

4310
   // Try to find a previous cast of this register to this type
4311
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,373,485✔
4312
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
140,515✔
4313
         return other->result;
15,604✔
4314
   }
4315

4316
   op_t *op = vcode_add_op(VCODE_OP_CAST);
53,799✔
4317
   vcode_add_arg(op, reg);
53,799✔
4318
   op->type  = type;
53,799✔
4319

4320
   static const vcode_type_t allowed[][2] = {
53,799✔
4321
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4322
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4323
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4324
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4325
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4326
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4327
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4328
   };
4329

4330
   if (integral) {
53,799✔
4331
      vtype_t *vt = vcode_type_data(type);
52,957✔
4332
      int64_t low = vt->low, high = vt->high;
52,957✔
4333

4334
      vstamp_t *rt = vcode_stamp_data(vcode_reg_data(reg)->stamp);
52,957✔
4335
      if (rt != NULL) {
52,957✔
4336
         VCODE_ASSERT(rt->kind == VCODE_STAMP_INT, "must be integer stamp");
12,742✔
4337
         low = MAX(low, rt->u.intg.low);
12,742✔
4338
         high = MIN(high, rt->u.intg.high);
12,742✔
4339
      }
4340

4341
      vstamp_t *bt = vcode_stamp_data(stamp);
52,957✔
4342
      if (bt != NULL) {
52,957✔
4343
         VCODE_ASSERT(bt->kind == VCODE_STAMP_INT, "must be integer stamp");
22,227✔
4344
         low = MAX(low, bt->u.intg.low);
22,227✔
4345
         high = MIN(high, bt->u.intg.high);
22,227✔
4346
      }
4347

4348
      stamp = vstamp_int(low, high);
52,957✔
4349
   }
4350

4351
   op->result = vcode_add_reg(type, stamp);
53,799✔
4352

4353
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
94,991✔
4354
      if (from == allowed[i][0] && to == allowed[i][1])
94,991✔
4355
         return op->result;
4356
   }
4357

UNCOV
4358
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4359
}
4360

4361
void emit_return(vcode_reg_t reg)
55,009✔
4362
{
4363
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
55,009✔
4364
   if (reg != VCODE_INVALID_REG) {
55,009✔
4365
      vcode_add_arg(op, reg);
24,393✔
4366

4367
      const vtype_kind_t rkind = vcode_reg_kind(reg);
24,393✔
4368
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY)
24,393✔
4369
         vcode_heap_allocate(reg);
4,401✔
4370

4371
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
24,393✔
4372
                   || active_unit->kind == VCODE_UNIT_THUNK
4373
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4374
                   "returning value fron non-function unit");
4375
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
24,393✔
4376
                    && rkind == VCODE_TYPE_INT)
4377
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4378
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4379
                       && rkind == VCODE_TYPE_ACCESS),
4380
                   "return value incorrect type");
4381
   }
4382
}
55,009✔
4383

4384
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
9,058✔
4385
                         vcode_reg_t values, vcode_reg_t reject,
4386
                         vcode_reg_t after)
4387
{
4388
   int64_t nconst;
9,058✔
4389
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
9,058✔
4390
      emit_comment("Skip empty waveform");
9✔
4391
      return;
9✔
4392
   }
4393

4394
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
9,049✔
4395
   vcode_add_arg(op, nets);
9,049✔
4396
   vcode_add_arg(op, nnets);
9,049✔
4397
   vcode_add_arg(op, values);
9,049✔
4398
   vcode_add_arg(op, reject);
9,049✔
4399
   vcode_add_arg(op, after);
9,049✔
4400

4401
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
9,049✔
4402
                "sched_waveform target is not signal");
4403
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
9,049✔
4404
                "sched_waveform net count is not offset type");
4405
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
9,049✔
4406
                "signal cannot be values argument for sched_waveform");
4407
}
4408

4409
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
70✔
4410
{
4411
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
70✔
4412
   vcode_add_arg(op, nets);
70✔
4413
   vcode_add_arg(op, nnets);
70✔
4414
   vcode_add_arg(op, values);
70✔
4415

4416
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
70✔
4417
                "force target is not signal");
4418
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
70✔
4419
                "force net count is not offset type");
4420
}
70✔
4421

4422
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
42✔
4423
{
4424
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
42✔
4425
   vcode_add_arg(op, nets);
42✔
4426
   vcode_add_arg(op, nnets);
42✔
4427

4428
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
42✔
4429
                "release target is not signal");
4430
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
42✔
4431
                "release net count is not offset type");
4432
}
42✔
4433

4434
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
24✔
4435
                     vcode_reg_t after)
4436
{
4437
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
24✔
4438
   vcode_add_arg(op, nets);
24✔
4439
   vcode_add_arg(op, nnets);
24✔
4440
   vcode_add_arg(op, reject);
24✔
4441
   vcode_add_arg(op, after);
24✔
4442

4443
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
24✔
4444
                "disconnect target is not signal");
4445
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
24✔
4446
                "disconnect net count is not offset type");
4447
}
24✔
4448

4449
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
32,614✔
4450
{
4451
   int64_t tconst;
32,614✔
4452
   if (vcode_reg_const(test, &tconst)) {
32,614✔
4453
      emit_jump(!!tconst ? btrue : bfalse);
3,819✔
4454
      return;
1,948✔
4455
   }
4456

4457
   op_t *op = vcode_add_op(VCODE_OP_COND);
30,666✔
4458
   vcode_add_arg(op, test);
30,666✔
4459
   vcode_add_target(op, btrue);
30,666✔
4460
   vcode_add_target(op, bfalse);
30,666✔
4461

4462
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
30,666✔
4463
                "cond test is not a bool");
4464
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
30,666✔
4465
                "invalid cond targets");
4466
}
4467

4468
vcode_reg_t emit_neg(vcode_reg_t lhs)
6,971✔
4469
{
4470
   int64_t lconst;
6,971✔
4471
   if (vcode_reg_const(lhs, &lconst))
6,971✔
UNCOV
4472
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4473

4474
   op_t *op = vcode_add_op(VCODE_OP_NEG);
6,971✔
4475
   vcode_add_arg(op, lhs);
6,971✔
4476
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
6,971✔
4477

4478
   return op->result;
6,971✔
4479
}
4480

4481
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
467✔
4482
{
4483
   int64_t lconst;
467✔
4484
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
467✔
UNCOV
4485
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4486

4487
   reg_t *lhs_r = vcode_reg_data(lhs);
467✔
4488

4489
   vstamp_t *s = vcode_stamp_data(lhs_r->stamp);
467✔
4490
   if (s != NULL && s->kind == VCODE_STAMP_INT && s->u.intg.low >= 0)
467✔
4491
      return emit_neg(lhs);   // Cannot overflow
210✔
4492

4493
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
257✔
4494
   vcode_add_arg(op, lhs);
257✔
4495
   vcode_add_arg(op, locus);
257✔
4496

4497
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
257✔
4498
                "locus argument to trap neg must be a debug locus");
4499
   VCODE_ASSERT(vtype_kind(lhs_r->type) == VCODE_TYPE_INT,
257✔
4500
                "trapping neg may only be used with integer types");
4501

4502
   return (op->result = vcode_add_reg(lhs_r->type, VCODE_INVALID_STAMP));
257✔
4503
}
4504

4505
vcode_reg_t emit_abs(vcode_reg_t lhs)
692✔
4506
{
4507
   int64_t lconst;
692✔
4508
   if (vcode_reg_const(lhs, &lconst))
692✔
4509
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4510

4511
   op_t *op = vcode_add_op(VCODE_OP_ABS);
691✔
4512
   vcode_add_arg(op, lhs);
691✔
4513
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
691✔
4514

4515
   return op->result;
691✔
4516
}
4517

4518
void emit_comment(const char *fmt, ...)
77,954✔
4519
{
4520
#ifndef NDEBUG
4521
   va_list ap;
77,954✔
4522
   va_start(ap, fmt);
77,954✔
4523

4524
   char *buf = xvasprintf(fmt, ap);
77,954✔
4525
   for (char *p = buf + strlen(buf) - 1;
77,954✔
4526
        p >= buf && isspace_iso88591(*p); p--)
77,954✔
UNCOV
4527
      *p = '\0';
×
4528

4529
   vcode_add_op(VCODE_OP_COMMENT)->comment = buf;
77,954✔
4530
   va_end(ap);
77,954✔
4531
#endif
4532
}
77,954✔
4533

4534
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
18,463✔
4535
                        vcode_reg_t rfalse)
4536
{
4537
   int64_t tconst;
18,463✔
4538
   if (vcode_reg_const(test, &tconst))
18,463✔
4539
      return !!tconst ? rtrue : rfalse;
4,730✔
4540
   else if (rtrue == rfalse)
13,733✔
4541
      return rtrue;
4542

4543
   // Find a previous identical select
4544
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
298,037✔
4545
      if (other->args.items[0] == test && other->args.items[1] == rtrue
10,878✔
4546
          && other->args.items[2] == rfalse)
649✔
4547
         return other->result;
556✔
4548
   }
4549

4550
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
13,002✔
4551
   vcode_add_arg(op, test);
13,002✔
4552
   vcode_add_arg(op, rtrue);
13,002✔
4553
   vcode_add_arg(op, rfalse);
13,002✔
4554
   op->result = vcode_add_reg(vcode_reg_type(rtrue), VCODE_INVALID_STAMP);
13,002✔
4555

4556
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
13,002✔
4557
                "select test must have bool type");
4558
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
13,002✔
4559
                "select arguments are not the same type");
4560

4561
   return op->result;
13,002✔
4562
}
4563

4564
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
442✔
4565
{
4566
   switch (op) {
442✔
4567
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
45✔
4568
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
349✔
4569
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
12✔
4570
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
12✔
4571
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
12✔
4572
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
12✔
4573
   default:
×
4574
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
4575
   }
4576
}
4577

4578
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
7,422✔
4579
{
4580
   vcode_type_t vtbool = vtype_bool();
7,422✔
4581

4582
   int64_t lconst, rconst;
7,422✔
4583
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
7,422✔
4584
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
7,422✔
4585
   if (l_is_const && r_is_const) {
7,422✔
4586
      switch (op) {
6✔
UNCOV
4587
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
UNCOV
4588
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
UNCOV
4589
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
×
4590
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
6✔
UNCOV
4591
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
UNCOV
4592
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
UNCOV
4593
      default:
×
4594
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4595
      }
4596
   }
4597
   else if (l_is_const)
7,416✔
4598
      return emit_logical_identity(op, rhs, !!lconst);
342✔
4599
   else if (r_is_const)
7,074✔
4600
      return emit_logical_identity(op, lhs, !!rconst);
100✔
4601
   else if (lhs == rhs) {
6,974✔
4602
      switch (op) {
27✔
4603
      case VCODE_OP_AND:
4604
      case VCODE_OP_OR:
4605
         return lhs;
4606
      case VCODE_OP_NAND:
6✔
4607
      case VCODE_OP_NOR:
4608
         return emit_not(lhs);
6✔
4609
      case VCODE_OP_XOR:
3✔
4610
         return emit_const(vtbool, 0);
3✔
UNCOV
4611
      case VCODE_OP_XNOR:
×
UNCOV
4612
         return emit_const(vtbool, 1);
×
UNCOV
4613
      default:
×
4614
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4615
      }
4616
   }
4617

4618
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
6,947✔
4619

4620
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
6,947✔
4621
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4622
                "arguments to %s are not boolean", vcode_op_string(op));
4623

4624
   return result;
4625
}
4626

4627
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
2,430✔
4628
{
4629
   return emit_logical(VCODE_OP_OR, lhs, rhs);
2,430✔
4630
}
4631

4632
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
4,768✔
4633
{
4634
   return emit_logical(VCODE_OP_AND, lhs, rhs);
4,768✔
4635
}
4636

4637
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
49✔
4638
{
4639
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
49✔
4640
}
4641

4642
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
50✔
4643
{
4644
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
50✔
4645
}
4646

4647
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
70✔
4648
{
4649
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
70✔
4650
}
4651

4652
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
55✔
4653
{
4654
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
55✔
4655
}
4656

4657
vcode_reg_t emit_not(vcode_reg_t arg)
2,487✔
4658
{
4659
   int64_t cval;
2,487✔
4660
   if (vcode_reg_const(arg, &cval))
2,487✔
4661
      return emit_const(vtype_bool(), !cval);
27✔
4662

4663
   op_t *op = vcode_add_op(VCODE_OP_NOT);
2,460✔
4664
   vcode_add_arg(op, arg);
2,460✔
4665

4666
   vcode_type_t vtbool = vtype_bool();
2,460✔
4667
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
2,460✔
4668
                "argument to not is not boolean");
4669

4670
   return (op->result = vcode_add_reg(vtbool, VCODE_INVALID_STAMP));
2,460✔
4671
}
4672

4673
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
47,071✔
4674
{
4675
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,737,002✔
4676
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
156,158✔
4677
         bool match = true;
4678
         for (int i = 0; match && i < ndims; i++) {
22,640✔
4679
            match = other->args.items[i*3 + 1] == dims[i].left
11,352✔
4680
               && other->args.items[i*3 + 2] == dims[i].right
9,154✔
4681
               && other->args.items[i*3 + 3] == dims[i].dir;
20,236✔
4682
         }
4683
         if (match)
11,288✔
4684
            return other->result;
8,820✔
4685
      }
4686
   }
4687

4688
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
38,251✔
4689
   vcode_add_arg(op, data);
38,251✔
4690
   for (int i = 0; i < ndims; i++) {
77,154✔
4691
      vcode_add_arg(op, dims[i].left);
38,903✔
4692
      vcode_add_arg(op, dims[i].right);
38,903✔
4693
      vcode_add_arg(op, dims[i].dir);
38,903✔
4694
   }
4695

4696
   vcode_type_t ptr_type = vcode_reg_type(data);
38,251✔
4697
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
38,251✔
4698
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
38,251✔
4699
                "wrapped data is not pointer or signal");
4700

4701
#ifdef DEBUG
4702
   for (int i = 0; i < ndims; i++) {
77,154✔
4703
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
38,903✔
4704
                   "dimension %d left bound must be scalar", i + 1);
4705
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
38,903✔
4706
                   "dimension %d right bound must be scalar", i + 1);
4707
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
38,903✔
4708
                   "dimension %d direction must be bool", i + 1);
4709
   }
4710
#endif
4711

4712
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
76,502✔
4713
      ? vtype_pointed(ptr_type) : ptr_type;
38,251✔
4714

4715
   op->result = vcode_add_reg(vtype_uarray(ndims, elem), vcode_reg_stamp(data));
38,251✔
4716

4717
   return op->result;
38,251✔
4718
}
4719

4720
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
104,268✔
4721
                                  vcode_reg_t array, unsigned dim,
4722
                                  unsigned arg_index)
4723
{
4724
   // Reuse any previous operation in this block with the same arguments
4725
   VCODE_FOR_EACH_OP(other) {
1,185,184✔
4726
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,140,172✔
4727
          && (rtype == VCODE_INVALID_TYPE
23,963✔
4728
              || vtype_eq(rtype, vcode_reg_type(other->result))))
10,362✔
4729
         return other->result;
23,963✔
4730
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,116,209✔
4731
         return other->args.items[1 + (dim * 3) + arg_index];
35,293✔
4732
   }
4733

4734
   op_t *op = vcode_add_op(o);
45,012✔
4735
   vcode_add_arg(op, array);
45,012✔
4736
   op->dim = dim;
45,012✔
4737

4738
   vcode_type_t atype = vcode_reg_type(array);
45,012✔
4739
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
45,012✔
4740
                "cannot use %s with non-uarray type", vcode_op_string(o));
4741

4742
   vtype_t *vt = vcode_type_data(atype);
45,012✔
4743
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
45,012✔
4744

4745
   if (rtype == VCODE_INVALID_TYPE)
45,012✔
4746
      rtype = vtype_offset();
29,074✔
4747

4748
   return (op->result = vcode_add_reg(rtype, VCODE_INVALID_STAMP));
45,012✔
4749
}
4750

4751
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
38,427✔
4752
{
4753
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
38,427✔
4754
                         array, dim, 0);
4755
}
4756

4757
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
27,676✔
4758
{
4759
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
27,676✔
4760
                         array, dim, 1);
4761
}
4762

4763
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
38,165✔
4764
{
4765
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
38,165✔
4766
                         array, dim, 2);
4767
}
4768

4769
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
46,327✔
4770
{
4771
   VCODE_FOR_EACH_OP(other) {
675,152✔
4772
      if (other->kind == VCODE_OP_UARRAY_LEN) {
653,396✔
4773
         if (other->args.items[0] == array && other->dim == dim)
41,371✔
4774
            return other->result;
9,651✔
4775
      }
4776
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
612,025✔
4777
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
14,920✔
4778
                      "array dimension %d out of bounds", dim);
4779

4780
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
14,920✔
4781
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
14,920✔
4782
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
14,920✔
4783
         return emit_range_length(left_reg, right_reg, dir_reg);
14,920✔
4784
      }
4785
   }
4786

4787
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
21,756✔
4788
   vcode_add_arg(op, array);
21,756✔
4789
   op->dim = dim;
21,756✔
4790

4791
   vcode_type_t atype = vcode_reg_type(array);
21,756✔
4792
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
21,756✔
4793
                "cannot use uarray len with non-uarray type");
4794

4795
   vtype_t *vt = vcode_type_data(atype);
21,756✔
4796
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
21,756✔
4797

4798
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
21,756✔
4799

4800
   return op->result;
21,756✔
4801
}
4802

4803
vcode_reg_t emit_unwrap(vcode_reg_t array)
35,684✔
4804
{
4805
   VCODE_FOR_EACH_OP(other) {
1,552,937✔
4806
      if (other->kind == VCODE_OP_WRAP && other->result == array)
1,527,524✔
4807
         return other->args.items[0];
8,528✔
4808
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
1,518,996✔
4809
         return other->result;
1,743✔
4810
   }
4811

4812
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
25,413✔
4813
   vcode_add_arg(op, array);
25,413✔
4814

4815
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
25,413✔
4816
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
25,413✔
4817
                "unwrap can only only be used with uarray types");
4818

4819
   vcode_type_t elem = vt->elem;
25,413✔
4820

4821
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
25,413✔
4822
      ? elem : vtype_pointer(elem);
25,413✔
4823

4824
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
25,413✔
4825
}
4826

4827
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
29,742✔
4828
                            vcode_reg_t dir)
4829
{
4830
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
1,442,100✔
UNCOV
4831
      if (other->args.items[0] == left
×
UNCOV
4832
          && other->args.items[1] == right
×
UNCOV
4833
          && other->args.items[2] == dir)
×
UNCOV
4834
         return other->result;
×
4835
   }
4836

4837
   int64_t dir_const, l_low, l_high, r_low, r_high;
29,742✔
4838
   if (vcode_reg_const(dir, &dir_const)
29,742✔
4839
       && vcode_reg_bounds(left, &l_low, &l_high)
26,719✔
4840
       && vcode_reg_bounds(right, &r_low, &r_high)) {
26,719✔
4841

4842
      if (dir_const == RANGE_TO && l_low > r_high)
26,719✔
4843
         return emit_const(vtype_bool(), 1);
56✔
4844
      else if (dir_const == RANGE_TO && l_high <= r_low)
26,663✔
4845
         return emit_const(vtype_bool(), 0);
18,614✔
4846
      else if (dir_const == RANGE_DOWNTO && r_low > l_high)
8,049✔
4847
         return emit_const(vtype_bool(), 1);
619✔
4848
      else if (dir_const == RANGE_DOWNTO && r_high <= l_low)
7,430✔
4849
         return emit_const(vtype_bool(), 0);
1,871✔
4850
      else if (dir_const == RANGE_TO)
5,559✔
4851
         return emit_cmp(VCODE_CMP_GT, left, right);
2,861✔
4852
      else
4853
         return emit_cmp(VCODE_CMP_GT, right, left);
2,698✔
4854
   }
4855

4856
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
3,023✔
4857
   vcode_add_arg(op, left);
3,023✔
4858
   vcode_add_arg(op, right);
3,023✔
4859
   vcode_add_arg(op, dir);
3,023✔
4860

4861
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
3,023✔
4862
                "range left and right have different types");
4863
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
3,023✔
4864
                "dir argument to range length is not int");
4865

4866
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
3,023✔
4867
}
4868

4869
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
14,958✔
4870
                              vcode_reg_t dir)
4871
{
4872
   vcode_reg_t left_array = VCODE_INVALID_REG,
14,958✔
4873
      right_array = VCODE_INVALID_REG,
14,958✔
4874
      dir_array = VCODE_INVALID_REG;
14,958✔
4875
   int left_dim = -1, right_dim = -1, dir_dim = -1;
14,958✔
4876

4877
   VCODE_FOR_EACH_OP(other) {
294,060✔
4878
      if (other->kind == VCODE_OP_RANGE_LENGTH
284,707✔
4879
          && other->args.items[0] == left
7,936✔
4880
          && other->args.items[1] == right
5,924✔
4881
          && other->args.items[2] == dir)
5,605✔
4882
         return other->result;
5,605✔
4883
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
279,102✔
4884
         left_array = other->args.items[0];
364✔
4885
         left_dim = other->dim;
364✔
4886
      }
4887
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
278,738✔
4888
         right_array = other->args.items[0];
364✔
4889
         right_dim = other->dim;
364✔
4890
      }
4891
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
278,374✔
4892
         dir_array = other->args.items[0];
735✔
4893
         dir_dim = other->dim;
735✔
4894
      }
4895
   }
4896

4897
   if (left_array != VCODE_INVALID_REG && left_array == right_array
9,353✔
4898
       && right_array == dir_array && left_dim == right_dim
364✔
4899
       && right_dim == dir_dim)
364✔
4900
      return emit_uarray_len(left_array, left_dim);
364✔
4901

4902
   int64_t lconst, rconst, dconst;
8,989✔
4903
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
8,989✔
4904
       && vcode_reg_const(right, &rconst)) {
4,920✔
4905

4906
      int64_t diff;
1,846✔
4907
      if (dconst == RANGE_TO)
1,846✔
4908
         diff = rconst - lconst;
1,553✔
4909
      else
4910
         diff = lconst - rconst;
293✔
4911

4912
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
1,846✔
4913
   }
4914

4915
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
7,143✔
4916
   vcode_add_arg(op, left);
7,143✔
4917
   vcode_add_arg(op, right);
7,143✔
4918
   vcode_add_arg(op, dir);
7,143✔
4919

4920
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
7,143✔
4921
                "range left and right have different types");
4922
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
7,143✔
4923
                "dir argument to range length is not int");
4924

4925
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
7,143✔
4926

4927
   return op->result;
7,143✔
4928
}
4929

4930
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
55,491✔
4931
{
4932
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
494,944✔
4933
      if (other->hops == hops && other->address == var)
67,413✔
4934
         return other->result;
11,522✔
4935
   }
4936

4937
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
43,969✔
4938
   op->hops    = hops;
43,969✔
4939
   op->address = var;
43,969✔
4940

4941
   VCODE_ASSERT(hops > 0, "invalid hop count");
43,969✔
4942

4943
   vcode_unit_t vu = active_unit;
43,969✔
4944
   for (int i = 0; i < hops; i++) {
96,888✔
4945
      vu = vu->context;
52,919✔
4946
      VCODE_ASSERT(vu, "hop count is greater than depth");
52,919✔
4947
   }
4948

4949
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
43,969✔
4950

4951
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
43,969✔
4952

4953
   return op->result;
43,969✔
4954
}
4955

4956
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
16,314✔
4957
                             vcode_reg_t size, vcode_reg_t value,
4958
                             vcode_reg_t flags, vcode_reg_t locus,
4959
                             vcode_reg_t offset)
4960
{
4961
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
16,314✔
4962
   vcode_add_arg(op, count);
16,314✔
4963
   vcode_add_arg(op, size);
16,314✔
4964
   vcode_add_arg(op, value);
16,314✔
4965
   vcode_add_arg(op, flags);
16,314✔
4966
   vcode_add_arg(op, locus);
16,314✔
4967
   if (offset != VCODE_INVALID_REG)
16,314✔
4968
      vcode_add_arg(op, offset);
5,787✔
4969

4970
   vcode_type_t vtype = vcode_reg_type(value);
16,314✔
4971
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
16,314✔
4972
   VCODE_ASSERT(vtype_eq(vtype, type)
16,314✔
4973
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4974
                "init signal value type does not match signal type");
4975
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
16,314✔
4976
                "locus argument to init signal must be a debug locus");
4977
   VCODE_ASSERT(offset == VCODE_INVALID_REG
16,314✔
4978
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4979
                "init signal offset argument must have pointer type");
4980

4981
   vcode_type_t stype = vtype_signal(type);
16,314✔
4982
   return (op->result = vcode_add_reg(stype, VCODE_INVALID_STAMP));
16,314✔
4983
}
4984

4985
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
3,406✔
4986
{
4987
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
3,406✔
4988
   vcode_add_arg(op, signal);
3,406✔
4989
   vcode_add_arg(op, resolution);
3,406✔
4990

4991
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
3,406✔
4992
                "signal argument has wrong type");
4993

4994
   vcode_type_t rtype = vcode_reg_type(resolution);
3,406✔
4995
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
3,406✔
4996
                "resolution wrapper argument must be pointer");
4997
   VCODE_ASSERT(vtype_kind(vtype_pointed(rtype)) == VCODE_TYPE_RESOLUTION,
3,406✔
4998
                "resolution wrapper argument has wrong type");
4999
}
3,406✔
5000

5001
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
75✔
5002
                                 vcode_reg_t size, vcode_reg_t locus,
5003
                                 vcode_reg_t kind, vcode_reg_t closure,
5004
                                 vcode_reg_t delay)
5005
{
5006
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
75✔
5007
   vcode_add_arg(op, count);
75✔
5008
   vcode_add_arg(op, size);
75✔
5009
   vcode_add_arg(op, locus);
75✔
5010
   vcode_add_arg(op, kind);
75✔
5011
   vcode_add_arg(op, closure);
75✔
5012
   vcode_add_arg(op, delay);
75✔
5013

5014
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
75✔
5015
                "count argument to implicit signal is not offset");
5016
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
75✔
5017
                "kind argument to implicit signal is not offset");
5018
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
75✔
5019
                "closure argument to implicit signal is not a closure");
5020
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
75✔
5021
                "locus argument to implicit signal must be a debug locus");
5022
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
75✔
5023
                "delay argument to implicit signal must be time");
5024

5025
   vcode_type_t stype = vtype_signal(type);
75✔
5026
   return (op->result = vcode_add_reg(stype, VCODE_INVALID_REG));
75✔
5027
}
5028

5029
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
5,456✔
5030
{
5031
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
5,456✔
5032
   vcode_add_arg(op, src);
5,456✔
5033
   vcode_add_arg(op, dst);
5,456✔
5034
   vcode_add_arg(op, count);
5,456✔
5035

5036
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
5,456✔
5037
                "src argument to map signal is not a signal");
5038
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
5,456✔
5039
                "dst argument to map signal is not a signal");
5040
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5,456✔
5041
                "count argument type to map signal is not offset");
5042
}
5,456✔
5043

5044
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
201✔
5045
{
5046
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
201✔
5047
   vcode_add_arg(op, src);
201✔
5048
   vcode_add_arg(op, dst);
201✔
5049
   vcode_add_arg(op, count);
201✔
5050

5051
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
201✔
5052
                "dst argument to map const is not a signal");
5053
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
201✔
5054
                "count argument type to map const is not offset");
5055
}
201✔
5056

5057
void emit_map_implicit(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
57✔
5058
{
5059
   op_t *op = vcode_add_op(VCODE_OP_MAP_IMPLICIT);
57✔
5060
   vcode_add_arg(op, src);
57✔
5061
   vcode_add_arg(op, dst);
57✔
5062
   vcode_add_arg(op, count);
57✔
5063

5064
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
57✔
5065
                "src argument to map implicit is not a signal");
5066
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
57✔
5067
                "dst argument to map implicit is not a signal");
5068
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
57✔
5069
                "count argument type to map implicit is not offset");
5070
}
57✔
5071

5072
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
7,115✔
5073
{
5074
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
90,427✔
5075
      if (other->args.items[0] == target && other->args.items[1] == count)
12,122✔
5076
         return;
5077
   }
5078

5079
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
7,112✔
5080
   vcode_add_arg(op, target);
7,112✔
5081
   vcode_add_arg(op, count);
7,112✔
5082

5083
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
7,112✔
5084
                "target argument to drive signal is not a signal");
5085
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
7,112✔
5086
                "count argument type to drive signal is not offset");
5087
}
5088

5089
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
497✔
5090
                          vcode_reg_t count, vcode_reg_t reject,
5091
                          vcode_reg_t after)
5092
{
5093
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
497✔
5094
   vcode_add_arg(op, target);
497✔
5095
   vcode_add_arg(op, source);
497✔
5096
   vcode_add_arg(op, count);
497✔
5097
   vcode_add_arg(op, reject);
497✔
5098
   vcode_add_arg(op, after);
497✔
5099

5100
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
497✔
5101
                "target argument to transfer signal is not a signal");
5102
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
497✔
5103
                "count argument type to transfer signal is not offset");
5104
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
497✔
5105
                "source argument to transfer signal is not a signal");
5106
}
497✔
5107

5108
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
5,213✔
5109
                                    vcode_reg_t nlits)
5110
{
5111
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
85,045✔
5112
      if (other->args.items[0] == closure && other->args.items[1] == nlits)
11,324✔
UNCOV
5113
         return other->result;
×
5114
   }
5115

5116
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
5,213✔
5117
                "first argument to resolution wrapper must be closure");
5118

5119
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
5,213✔
5120
   vcode_add_arg(op, closure);
5,213✔
5121
   vcode_add_arg(op, nlits);
5,213✔
5122

5123
   return (op->result = vcode_add_reg(vtype_resolution(type),
5,213✔
5124
                                      VCODE_INVALID_STAMP));
5125
}
5126

5127
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t rtype)
5,510✔
5128
{
5129
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
86,135✔
5130
      if (other->func == func && other->args.items[0] == context)
11,495✔
UNCOV
5131
         return other->result;
×
5132
   }
5133

5134
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
5,510✔
5135
   vcode_add_arg(op, context);
5,510✔
5136
   op->func = func;
5,510✔
5137

5138
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5,510✔
5139
                "invalid closure context argument");
5140

5141
   return (op->result = vcode_add_reg(vtype_closure(rtype),
5,510✔
5142
                                      VCODE_INVALID_STAMP));
5143
}
5144

5145
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
35,568✔
5146
{
5147
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
71,871✔
5148
      if (other->func == name)
29,052✔
5149
         return other->result;
13,599✔
5150
   }
5151

5152
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
21,969✔
5153
   op->func = name;
21,969✔
5154
   if (context != VCODE_INVALID_REG)
21,969✔
5155
      vcode_add_arg(op, context);
190✔
5156

5157
   VCODE_ASSERT(context == VCODE_INVALID_REG
21,969✔
5158
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5159
                "invalid protected init context argument");
5160
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
21,969✔
5161
                || active_unit->kind == VCODE_UNIT_PACKAGE
5162
                || active_unit->kind == VCODE_UNIT_THUNK,
5163
                "cannot use package init here");
5164
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
21,969✔
5165

5166
   return (op->result = vcode_add_reg(vtype_context(name),
21,969✔
5167
                                      VCODE_INVALID_STAMP));
5168
}
5169

5170
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
550✔
5171
                                vcode_reg_t path_name, vcode_reg_t inst_name)
5172
{
5173
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
550✔
5174
   vcode_add_arg(op, context);
550✔
5175
   op->func = vtype_name(type);
550✔
5176

5177
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
550✔
5178
      vcode_add_arg(op, path_name);
420✔
5179
      vcode_add_arg(op, inst_name);
420✔
5180

5181
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
420✔
5182
                   "path name argument must be uarray");
5183
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
420✔
5184
                   "inst name argument must be uarray");
5185
   }
5186

5187
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
550✔
5188
                "protected init type must be context");
5189
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
550✔
5190
                "invalid protected init context argument");
5191

5192
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
550✔
5193
}
5194

5195
void emit_process_init(ident_t name, vcode_reg_t locus)
117✔
5196
{
5197
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
117✔
5198
   vcode_add_arg(op, locus);
117✔
5199
   op->func = name;
117✔
5200

5201
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
117✔
5202
                "locus argument to process init must be a debug locus");
5203
}
117✔
5204

5205
void emit_protected_free(vcode_reg_t obj)
308✔
5206
{
5207
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
308✔
5208
   vcode_add_arg(op, obj);
308✔
5209

5210
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
308✔
5211
                "protected object type must be context");
5212
}
308✔
5213

5214
vcode_reg_t emit_context_upref(int hops)
19,665✔
5215
{
5216
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
134,390✔
5217
      if (other->hops == hops)
8,799✔
5218
         return other->result;
8,751✔
5219
   }
5220

5221
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
10,914✔
5222
   op->hops = hops;
10,914✔
5223

5224
   VCODE_ASSERT(hops >= 0, "invalid hop count");
10,914✔
5225

5226
   vcode_unit_t vu = active_unit;
10,914✔
5227
   for (int i = 0; i < hops; i++) {
19,181✔
5228
      vu = vu->context;
8,267✔
5229
      VCODE_ASSERT(vu, "hop count is greater than depth");
8,267✔
5230
   }
5231

5232
   return (op->result = vcode_add_reg(vtype_context(vu->name),
10,914✔
5233
                                      VCODE_INVALID_STAMP));
5234
}
5235

5236
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
655✔
5237
                                    vcode_reg_t len)
5238
{
5239
   op_t *op = vcode_add_op(opkind);
655✔
5240
   vcode_add_arg(op, nets);
655✔
5241
   vcode_add_arg(op, len);
655✔
5242

5243
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
655✔
5244
                "argument to %s is not a signal", vcode_op_string(opkind));
5245

5246
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
655✔
5247
}
5248

5249
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
438✔
5250
{
5251
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
438✔
5252
}
5253

5254
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
217✔
5255
{
5256
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
217✔
5257
}
5258

5259
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
37,125✔
5260
{
5261
   // Try scanning backwards through the block for another record ref
5262
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
2,692,908✔
5263
      if (other->args.items[0] == record && other->field == field)
504,835✔
5264
         return other->result;
3,866✔
5265
   }
5266

5267
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
33,259✔
5268
   op->field = field;
33,259✔
5269
   vcode_add_arg(op, record);
33,259✔
5270

5271
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
33,259✔
5272

5273
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
33,259✔
5274
                "argument to record ref must be a pointer");
5275

5276
   vtype_t *rtype = vcode_type_data(rptype->pointed);
33,259✔
5277
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
33,259✔
5278
                "argument must be pointer to record or record signal");
5279

5280
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
33,259✔
5281

5282
   vcode_type_t field_type  = rtype->fields.items[field];
33,259✔
5283
   vcode_type_t result_type = field_type;
33,259✔
5284

5285
   const vtype_kind_t fkind = vtype_kind(field_type);
33,259✔
5286
   if (fkind == VCODE_TYPE_CARRAY)
33,259✔
5287
      result_type = vtype_elem(field_type);
4,633✔
5288
   else if (fkind == VCODE_TYPE_UARRAY)
5289
      result_type = field_type;
5290

5291
   op->result = vcode_add_reg(vtype_pointer(result_type), VCODE_INVALID_STAMP);
33,259✔
5292

5293
   return op->result;
33,259✔
5294
}
5295

5296
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
33,009✔
5297
{
5298
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
1,662,019✔
5299
      if (other->args.items[0] == array && other->args.items[1] == offset)
104,363✔
5300
         return other->result;
1,212✔
5301
   }
5302

5303
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
31,797✔
5304
   vcode_add_arg(op, array);
31,797✔
5305
   vcode_add_arg(op, offset);
31,797✔
5306

5307
   vcode_type_t rtype = vcode_reg_type(array);
31,797✔
5308
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
31,797✔
5309
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5310
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5311
                "argument to array ref must be a pointer or signal");
5312
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
31,797✔
5313
                "array ref offset argument must have offset type");
5314

5315
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
31,797✔
5316
}
5317

5318
vcode_reg_t emit_table_ref(vcode_reg_t array, vcode_reg_t stride,
720✔
5319
                           const vcode_reg_t *args, int nargs)
5320
{
5321
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_TABLE_REF) {
21,069✔
5322
      if (other->args.items[0] != array || other->args.items[1] != stride)
851✔
5323
         continue;
598✔
5324
      else if (other->args.count != nargs + 2)
253✔
UNCOV
5325
         continue;
×
5326

5327
      bool match = true;
5328
      for (int i = 0; i < nargs; i++)
649✔
5329
         match &= (other->args.items[i + 2] == args[i]);
396✔
5330

5331
      if (match)
253✔
5332
         return other->result;
26✔
5333
   }
5334

5335
   op_t *op = vcode_add_op(VCODE_OP_TABLE_REF);
694✔
5336
   vcode_add_arg(op, array);
694✔
5337
   vcode_add_arg(op, stride);
694✔
5338
   for (int i = 0; i < nargs; i++)
1,729✔
5339
      vcode_add_arg(op, args[i]);
1,035✔
5340

5341
   vcode_type_t rtype = vcode_reg_type(array);
694✔
5342
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER
694✔
5343
                && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY,
5344
                "argument to table ref must be a pointer or signal");
5345
   VCODE_ASSERT(vcode_reg_kind(stride) == VCODE_TYPE_OFFSET,
694✔
5346
                "table ref stride argument must have offset type");
5347

5348
   for (int i = 0; i < nargs; i++)
1,729✔
5349
      VCODE_ASSERT(vtype_is_integral(vcode_reg_type(args[i])),
1,035✔
5350
                   "table ref indices must be integral");
5351

5352
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
694✔
5353
}
5354

5355
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
30,569✔
5356
{
5357
   int64_t cconst;
30,569✔
5358
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
30,569✔
5359
       && cconst == 0)
20,606✔
5360
      return;
5,374✔
5361
   else if (dest == src)
29,818✔
5362
      return;
5363

5364
   op_t *op = vcode_add_op(VCODE_OP_COPY);
25,195✔
5365
   vcode_add_arg(op, dest);
25,195✔
5366
   vcode_add_arg(op, src);
25,195✔
5367
   if (count != VCODE_INVALID_REG)
25,195✔
5368
      vcode_add_arg(op, count);
23,614✔
5369

5370
   vcode_type_t dtype = vcode_reg_type(dest);
25,195✔
5371
   vcode_type_t stype = vcode_reg_type(src);
25,195✔
5372

5373
   vtype_kind_t dkind = vtype_kind(dtype);
25,195✔
5374
   vtype_kind_t skind = vtype_kind(stype);
25,195✔
5375

5376
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
25,195✔
5377
                "destination type is not a pointer or access");
5378
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
25,195✔
5379
                "source type is not a pointer or access");
5380
   VCODE_ASSERT(vtype_eq(dtype, stype),
25,195✔
5381
                "source and destination types do not match");
5382
   VCODE_ASSERT(count == VCODE_INVALID_REG
25,195✔
5383
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5384
                "count is not offset type");
5385

5386
   op->type = vtype_pointed(dtype);
25,195✔
5387
}
5388

5389
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
4,328✔
5390
{
5391
   VCODE_FOR_EACH_OP(other) {
60,805✔
5392
      if (other->kind == VCODE_OP_CLEAR_EVENT)
56,531✔
5393
         break;
5394
      else if (other->kind == VCODE_OP_SCHED_EVENT
56,483✔
5395
               && other->args.items[0] == nets
2,479✔
5396
               && other->args.items[1] == n_elems)
9✔
5397
         return;
5398
   }
5399

5400
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
4,322✔
5401
   vcode_add_arg(op, nets);
4,322✔
5402
   vcode_add_arg(op, n_elems);
4,322✔
5403

5404
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
4,322✔
5405
                "nets argument to sched event must be signal");
5406
}
5407

5408
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
548✔
5409
{
5410
   VCODE_FOR_EACH_OP(other) {
2,516✔
5411
      if (other->kind == VCODE_OP_SCHED_EVENT)
1,968✔
5412
         break;
5413
      else if (other->kind == VCODE_OP_CLEAR_EVENT
1,968✔
5414
               && other->args.items[0] == nets
39✔
UNCOV
5415
               && other->args.items[1] == n_elems)
×
5416
         return;
5417
   }
5418

5419
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
548✔
5420
   vcode_add_arg(op, nets);
548✔
5421
   vcode_add_arg(op, n_elems);
548✔
5422

5423
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
548✔
5424
                "nets argument to clear event must be signal");
5425
}
5426

5427
void emit_sched_process(vcode_reg_t delay)
5,305✔
5428
{
5429
   op_t *op = vcode_add_op(VCODE_OP_SCHED_PROCESS);
5,305✔
5430
   vcode_add_arg(op, delay);
5,305✔
5431

5432
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
5,305✔
5433
                "delay must have integer type");
5434
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
5,305✔
5435
                || active_unit->kind == VCODE_UNIT_PROCESS,
5436
                "sched process only allowed in process or procedure");
5437
}
5,305✔
5438

5439
void emit_resume(ident_t func)
847✔
5440
{
5441
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
847✔
5442
   op->func = func;
847✔
5443

5444
   block_t *b = &(active_unit->blocks.items[active_block]);
847✔
5445
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
847✔
5446
}
847✔
5447

5448
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
5,517✔
5449
{
5450
   int64_t lconst;
5,517✔
5451
   if (vcode_reg_const(len, &lconst) && lconst == 0)
5,517✔
5452
      return;
29✔
5453

5454
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
5,488✔
5455
   vcode_add_arg(op, ptr);
5,488✔
5456
   vcode_add_arg(op, value);
5,488✔
5457
   vcode_add_arg(op, len);
5,488✔
5458

5459
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
5,488✔
5460
                "target of memset must have pointer type");
5461
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
5,488✔
5462
                "value of memset must have scalar type");
5463
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
5,488✔
5464
                "length of memset must have offset type");
5465
}
5466

5467
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
651✔
5468
               const vcode_block_t *blocks, int ncases)
5469
{
5470
   int64_t cval1, cval2;
651✔
5471
   bool is_const = vcode_reg_const(value, &cval1);
651✔
5472

5473
   for (int i = 0; i < ncases; i++) {
3,728✔
5474
      bool can_fold = false;
3,077✔
5475
      if (cases[i] == value)
3,077✔
5476
         can_fold = true;
5477
      else if (is_const && vcode_reg_const(cases[i], &cval2))
3,077✔
UNCOV
5478
         can_fold = (cval1 == cval2);
×
5479

UNCOV
5480
      if (can_fold) {
×
UNCOV
5481
         emit_jump(blocks[i]);
×
UNCOV
5482
         return;
×
5483
      }
5484
   }
5485

5486
   if (is_const) {
651✔
UNCOV
5487
      emit_jump(def);
×
UNCOV
5488
      return;
×
5489
   }
5490

5491
   op_t *op = vcode_add_op(VCODE_OP_CASE);
651✔
5492
   vcode_add_arg(op, value);
651✔
5493
   vcode_add_target(op, def);
651✔
5494

5495
   for (int i = 0; i < ncases; i++) {
3,728✔
5496
      vcode_add_arg(op, cases[i]);
3,077✔
5497
      vcode_add_target(op, blocks[i]);
3,077✔
5498

5499
#ifdef DEBUG
5500
      for (int j = 0; j < i; j++)
15,695✔
5501
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
12,618✔
5502
#endif
5503
   }
5504
}
5505

5506
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
1,236✔
5507
                    vcode_reg_t kind, vcode_reg_t status)
5508
{
5509
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
1,236✔
5510
   vcode_add_arg(op, file);
1,236✔
5511
   vcode_add_arg(op, name);
1,236✔
5512
   vcode_add_arg(op, length);
1,236✔
5513
   vcode_add_arg(op, kind);
1,236✔
5514
   if (status != VCODE_INVALID_REG)
1,236✔
5515
      vcode_add_arg(op, status);
25✔
5516

5517
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
1,236✔
5518
                "file open first argument must have file pointer type");
5519
}
1,236✔
5520

5521
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
267✔
5522
{
5523
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
267✔
5524
   vcode_add_arg(op, file);
267✔
5525
   vcode_add_arg(op, value);
267✔
5526
   if (length != VCODE_INVALID_REG)
267✔
5527
      vcode_add_arg(op, length);
210✔
5528

5529
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
267✔
5530
                "file write first argument must have file pointer type");
5531
}
267✔
5532

5533
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
90✔
5534
                    vcode_reg_t inlen, vcode_reg_t outlen)
5535
{
5536
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
90✔
5537
   vcode_add_arg(op, file);
90✔
5538
   vcode_add_arg(op, ptr);
90✔
5539
   if (inlen != VCODE_INVALID_REG) {
90✔
5540
      vcode_add_arg(op, inlen);
42✔
5541
      if (outlen != VCODE_INVALID_REG)
42✔
5542
         vcode_add_arg(op, outlen);
33✔
5543
   }
5544

5545
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
90✔
5546
                "file read first argument must have file pointer type");
5547
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
90✔
5548
                "file read pointer argument must have pointer type");
5549
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
90✔
5550
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5551
                "file read outlen argument must have pointer type");
5552
}
90✔
5553

5554
vcode_reg_t emit_null(vcode_type_t type)
13,077✔
5555
{
5556
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
259,440✔
5557
      if (vtype_eq(vcode_reg_type(other->result), type))
7,954✔
5558
         return other->result;
4,184✔
5559
   }
5560

5561
   op_t *op = vcode_add_op(VCODE_OP_NULL);
8,893✔
5562
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
8,893✔
5563

5564
   vtype_kind_t kind = vtype_kind(type);
8,893✔
5565
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
8,893✔
5566
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5567
                "null type must be file, access, context, or pointer");
5568

5569
   return op->result;
5570
}
5571

5572
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
654✔
5573
{
5574
   op_t *op = vcode_add_op(VCODE_OP_NEW);
654✔
5575
   if (length != VCODE_INVALID_REG)
654✔
5576
      vcode_add_arg(op, length);
563✔
5577

5578
   op->result = vcode_add_reg(vtype_access(type), VCODE_INVALID_STAMP);
654✔
5579

5580
   vtype_kind_t kind = vtype_kind(type);
654✔
5581
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
654✔
5582
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5583
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5584
                "new type must be int, real, record, access, or uarray");
5585
   VCODE_ASSERT(length == VCODE_INVALID_REG
654✔
5586
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5587
                "new length must have offset type");
5588

5589
   return op->result;
654✔
5590
}
5591

5592
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
2,946✔
5593
{
5594
   VCODE_FOR_EACH_OP(other) {
120,031✔
5595
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
117,832✔
5596
         return;
5597
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
117,414✔
5598
         return;
5599
   }
5600

5601
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
2,199✔
5602
   vcode_add_arg(op, ptr);
2,199✔
5603
   vcode_add_arg(op, locus);
2,199✔
5604

5605
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
2,199✔
5606
                "null check argument must be an access");
5607
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,199✔
5608
                "locus argument to null check must be a debug locus");
5609
}
5610

5611
void emit_deallocate(vcode_reg_t ptr)
347✔
5612
{
5613
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
347✔
5614
   vcode_add_arg(op, ptr);
347✔
5615

5616
   vcode_type_t ptype = vcode_reg_type(ptr);
347✔
5617
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
347✔
5618
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5619
                "deallocate argument must be pointer to access");
5620
}
347✔
5621

5622
vcode_reg_t emit_all(vcode_reg_t reg)
3,600✔
5623
{
5624
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
167,959✔
5625
      if (other->args.items[0] == reg)
10,279✔
5626
         return other->result;
747✔
5627
   }
5628

5629
   op_t *op = vcode_add_op(VCODE_OP_ALL);
2,853✔
5630
   vcode_add_arg(op, reg);
2,853✔
5631

5632
   vcode_type_t vtype = vcode_reg_type(reg);
2,853✔
5633

5634
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
2,853✔
5635
                "all argument must be an access");
5636

5637
   vcode_type_t pointed = vtype_pointed(vtype);
2,853✔
5638
   op->result = vcode_add_reg(vtype_pointer(pointed), vcode_reg_stamp(reg));
2,853✔
5639

5640
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
2,853✔
5641
                "cannot dereference opaque type");
5642

5643
   return op->result;
5644
}
5645

5646
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
13,581✔
5647
{
5648
   block_t *b = &(active_unit->blocks.items[active_block]);
13,581✔
5649
   for (int i = b->ops.count - 1; i >= 0; i--) {
324,346✔
5650
      const op_t *other = &(b->ops.items[i]);
311,329✔
5651
      if (other->kind == kind && other->args.items[0] == sig)
311,329✔
5652
         return other->result;
564✔
5653
   }
5654

5655
   op_t *op = vcode_add_op(kind);
13,017✔
5656
   vcode_add_arg(op, sig);
13,017✔
5657

5658
   vcode_type_t stype = vcode_reg_type(sig);
13,017✔
5659
   op->type = stype;
13,017✔
5660

5661
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
13,017✔
5662
                "argument r%d to resolved is not a signal", sig);
5663

5664
   vcode_type_t rtype = vtype_base(stype);
13,017✔
5665

5666
   const vtype_kind_t rkind = vtype_kind(rtype);
13,017✔
5667
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
13,017✔
UNCOV
5668
      rtype = vtype_elem(rtype);
×
5669

5670
   VCODE_ASSERT(vtype_is_scalar(rtype),
13,017✔
5671
                "resolved signal base type must be scalar");
5672

5673
   op->result = vcode_add_reg(vtype_pointer(rtype), vcode_reg_stamp(sig));
13,017✔
5674

5675
   return op->result;
13,017✔
5676
}
5677

5678
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
13,394✔
5679
{
5680
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
13,394✔
5681
}
5682

5683
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
187✔
5684
{
5685
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
187✔
5686
}
5687

5688
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
42✔
5689
{
5690
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
42✔
5691
   vcode_add_arg(op, signal);
42✔
5692
   if (len != VCODE_INVALID_REG)
42✔
5693
      vcode_add_arg(op, len);
9✔
5694

5695
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
42✔
5696
                "signal argument to last event must have signal type");
5697
   VCODE_ASSERT(len == VCODE_INVALID_REG
42✔
5698
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5699
                "length argument to last event must have offset type");
5700

5701
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
42✔
5702
}
5703

5704
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
45✔
5705
{
5706
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
45✔
5707
   vcode_add_arg(op, signal);
45✔
5708
   if (len != VCODE_INVALID_REG)
45✔
5709
      vcode_add_arg(op, len);
6✔
5710

5711
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
45✔
5712
                "signal argument to last active must have signal type");
5713
   VCODE_ASSERT(len == VCODE_INVALID_REG
45✔
5714
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5715
                "length argument to last active must have offset type");
5716

5717
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
45✔
5718
}
5719

5720
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,302✔
5721
{
5722
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,302✔
5723
   vcode_add_arg(op, signal);
4,302✔
5724
   vcode_add_arg(op, locus);
4,302✔
5725

5726
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,302✔
5727
                "signal argument must have signal type");
5728
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
4,302✔
5729
                "locus argument must have debug locus type");
5730
}
4,302✔
5731

5732
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
36✔
5733
{
5734
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
36✔
5735
   vcode_add_arg(op, signal);
36✔
5736
   vcode_add_arg(op, len);
36✔
5737

5738
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5739
                "signal argument to last active must have signal type");
5740
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
36✔
5741
                "length argument to last active must have offset type");
5742

5743
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
36✔
5744
}
5745

5746
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
120✔
5747
{
5748
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
120✔
5749
   vcode_add_arg(op, signal);
120✔
5750
   if (len != VCODE_INVALID_REG)
120✔
5751
      vcode_add_arg(op, len);
36✔
5752

5753
   vcode_type_t signal_type = vcode_reg_type(signal);
120✔
5754

5755
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
120✔
5756
                "signal argument to last active must have signal type");
5757
   VCODE_ASSERT(len == VCODE_INVALID_REG
120✔
5758
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5759
                "length argument to last active must have offset type");
5760

5761
   vcode_type_t base_type = vtype_base(signal_type);
120✔
5762
   op->result = vcode_add_reg(vtype_pointer(base_type), VCODE_INVALID_STAMP);
120✔
5763

5764
   return op->result;
120✔
5765
}
5766

5767
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
33,105✔
5768
                       vcode_reg_t dim)
5769
{
5770
   if (rlen == llen)
33,105✔
5771
      return;
5772

5773
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
200,688✔
5774
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
2,693✔
5775
         return;
5776
   }
5777

5778
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
7,299✔
5779
   vcode_add_arg(op, llen);
7,299✔
5780
   vcode_add_arg(op, rlen);
7,299✔
5781
   vcode_add_arg(op, locus);
7,299✔
5782
   if (dim != VCODE_INVALID_REG)
7,299✔
5783
      vcode_add_arg(op, dim);
27✔
5784

5785
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
7,299✔
5786
                "locus argument to length check must be a debug locus");
5787
}
5788

5789
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
411✔
5790
{
5791
   int64_t cval;
411✔
5792
   if (vcode_reg_const(exp, &cval) && cval >= 0)
411✔
5793
      return;
47✔
5794

5795
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
4,195✔
5796
      if (other->args.items[0] == exp)
12✔
5797
         return;
5798
   }
5799

5800
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
364✔
5801
   vcode_add_arg(op, exp);
364✔
5802
   vcode_add_arg(op, locus);
364✔
5803

5804
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
364✔
5805
                "exp argument to exponent check must be a integer");
5806
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
364✔
5807
                "locus argument to exponent check must be a debug locus");
5808
}
5809

5810
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
2,518✔
5811
{
5812
   int64_t cval;
2,518✔
5813
   if (vcode_reg_const(denom, &cval) && cval != 0)
2,518✔
5814
      return;
2,430✔
5815

5816
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
2,296✔
5817
      if (other->args.items[0] == denom)
48✔
5818
         return;
5819
   }
5820

5821
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
88✔
5822
   vcode_add_arg(op, denom);
88✔
5823
   vcode_add_arg(op, locus);
88✔
5824

5825
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
88✔
5826
                "denom argument to zero check must be a integer");
5827
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
88✔
5828
                "locus argument to zero check must be a debug locus");
5829
}
5830

5831
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
85,210✔
5832
                                   vcode_reg_t right, vcode_reg_t dir)
5833
{
5834
   int64_t dconst;
85,210✔
5835
   if (!vcode_reg_const(dir, &dconst))
85,210✔
5836
      return false;
5837

5838
   int64_t lconst, rconst;
75,263✔
5839
   if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
75,263✔
5840
      const bool is_null = (dconst == RANGE_TO && lconst > rconst)
51,078✔
5841
         || (dconst == RANGE_DOWNTO && rconst > lconst);
105,044✔
5842

5843
      int64_t low, high;
53,967✔
5844
      if (vcode_reg_bounds(reg, &low, &high)) {
53,967✔
5845
         const bool ok_static =
107,934✔
5846
            (dconst == RANGE_TO && low >= lconst && high <= rconst)
51,078✔
5847
            || (dconst == RANGE_DOWNTO && low >= rconst && high <= lconst)
8,629✔
5848
            || (!is_null && (reg == left || reg == right));
60,028✔
5849

5850
         return ok_static;
53,967✔
5851
      }
5852
   }
5853
   else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
21,296✔
5854
      vstamp_t *lbounds = vcode_stamp_data(vcode_reg_data(left)->stamp);
19,203✔
5855
      vstamp_t *rbounds = vcode_stamp_data(vcode_reg_data(right)->stamp);
19,203✔
5856

5857
      assert(lbounds->kind == VCODE_STAMP_REAL);
19,203✔
5858
      assert(rbounds->kind == VCODE_STAMP_REAL);
19,203✔
5859

5860
      double low, high;
19,203✔
5861

5862
      reg_t *rr = vcode_reg_data(reg);
19,203✔
5863
      vstamp_t *bounds = vcode_stamp_data(rr->stamp);
19,203✔
5864
      if (bounds != NULL) {
19,203✔
5865
         assert(bounds->kind == VCODE_STAMP_REAL);
12,601✔
5866
         low = bounds->u.real.low;
12,601✔
5867
         high = bounds->u.real.high;
12,601✔
5868
      }
5869
      else {
5870
         vtype_t *type = vcode_type_data(rr->type);
6,602✔
5871
         assert(type->kind == VCODE_TYPE_REAL);
6,602✔
5872
         low = type->rlow;
6,602✔
5873
         high = type->rhigh;
6,602✔
5874
      }
5875

5876
      if (isfinite(low) && lbounds->u.real.low == -DBL_MAX
19,203✔
5877
          && isfinite(high) && rbounds->u.real.high == DBL_MAX) {
18,489✔
5878
         // Covers the complete double range so can never overflow
5879
         return true;
18,489✔
5880
      }
5881
   }
5882

5883
   return false;
5884
}
5885

5886
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
86,115✔
5887
                              vcode_reg_t left, vcode_reg_t right,
5888
                              vcode_reg_t dir, vcode_reg_t locus,
5889
                              vcode_reg_t hint)
5890
{
5891
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
3,683,623✔
5892
      if (other->args.items[0] == reg && other->args.items[1] == left
18,319✔
5893
          && other->args.items[2] == right && other->args.items[3] == dir)
1,074✔
5894
         return;
5895
   }
5896

5897
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
85,210✔
5898
      emit_comment("Elided bounds check for r%d", reg);
66,395✔
5899
      return;
66,395✔
5900
   }
5901

5902
   op_t *op = vcode_add_op(kind);
18,815✔
5903
   vcode_add_arg(op, reg);
18,815✔
5904
   vcode_add_arg(op, left);
18,815✔
5905
   vcode_add_arg(op, right);
18,815✔
5906
   vcode_add_arg(op, dir);
18,815✔
5907
   vcode_add_arg(op, locus);
18,815✔
5908
   vcode_add_arg(op, hint);
18,815✔
5909

5910
   VCODE_ASSERT(vtype_is_numeric(vcode_reg_type(reg)),
18,815✔
5911
                "argument to bounds check must be numeric");
5912
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
18,815✔
5913
                "locus argument to bounds check must be a debug locus");
5914
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
18,815✔
5915
                "hint argument to bounds check must be a debug locus");
5916
}
5917

5918
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
22,564✔
5919
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5920
{
5921
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
22,564✔
5922
}
22,564✔
5923

5924
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
63,551✔
5925
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5926
{
5927
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
63,551✔
5928
}
63,551✔
5929

5930
void emit_dir_check(vcode_reg_t reg, vcode_reg_t dir, vcode_reg_t locus)
3,265✔
5931
{
5932
   if (reg == dir)
3,265✔
5933
      return;
5934

5935
   op_t *op = vcode_add_op(VCODE_OP_DIR_CHECK);
2,380✔
5936
   vcode_add_arg(op, reg);
2,380✔
5937
   vcode_add_arg(op, dir);
2,380✔
5938
   vcode_add_arg(op, locus);
2,380✔
5939

5940
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,380✔
5941
                "locus argument to dir check must be a debug locus");
5942
}
5943

5944
void emit_package_scope(vcode_reg_t locus)
45✔
5945
{
5946
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
45✔
5947
   vcode_add_arg(op, locus);
45✔
5948

5949
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5950
                "locus argument to package scope must be a debug locus");
5951
}
45✔
5952

5953
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
654✔
5954
{
5955
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
654✔
5956
   vcode_add_arg(op, locus);
654✔
5957
   op->type = type;
654✔
5958

5959
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
654✔
5960
                "locus argument to array scope must be a debug locus");
5961
}
654✔
5962

5963
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
1,718✔
5964
{
5965
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
1,718✔
5966
   vcode_add_arg(op, locus);
1,718✔
5967
   op->type = type;
1,718✔
5968

5969
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,718✔
5970
                "locus argument to record scope must be a debug locus");
5971
}
1,718✔
5972

5973
void emit_pop_scope(void)
2,417✔
5974
{
5975
   vcode_add_op(VCODE_OP_POP_SCOPE);
2,417✔
5976
}
2,417✔
5977

5978
vcode_reg_t emit_debug_locus(object_t *obj)
176,064✔
5979
{
5980
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
6,678,952✔
5981
      if (other->object == obj)
823,706✔
5982
         return other->result;
18,881✔
5983
   }
5984

5985
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
157,183✔
5986
   op->object = obj;
157,183✔
5987
   op->result = vcode_add_reg(vtype_debug_locus(), VCODE_INVALID_STAMP);
157,183✔
5988

5989
   return op->result;
157,183✔
5990
}
5991

UNCOV
5992
void emit_debug_out(vcode_reg_t reg)
×
5993
{
UNCOV
5994
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
UNCOV
5995
   vcode_add_arg(op, reg);
×
UNCOV
5996
}
×
5997

5998
void emit_cover_stmt(vcode_reg_t counters, uint32_t tag)
1,195✔
5999
{
6000
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,195✔
6001
   vcode_add_arg(op, counters);
1,195✔
6002
   op->tag = tag;
1,195✔
6003

6004
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
1,195✔
6005
                "counters argument must be pointer");
6006
}
1,195✔
6007

6008
void emit_cover_branch(vcode_reg_t counters, uint32_t tag)
509✔
6009
{
6010
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
509✔
6011
   vcode_add_arg(op, counters);
509✔
6012
   op->tag = tag;
509✔
6013

6014
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
509✔
6015
                "counters argument must be pointer");
6016
}
509✔
6017

6018
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
321✔
6019
{
6020
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
321✔
6021
   vcode_add_arg(op, signal);
321✔
6022
   op->tag = tag;
321✔
6023
}
321✔
6024

6025
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
12✔
6026
{
6027
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
12✔
6028
   vcode_add_arg(op, signal);
12✔
6029
   vcode_add_arg(op, low);
12✔
6030
   op->tag = tag;
12✔
6031
}
12✔
6032

6033
void emit_cover_expr(vcode_reg_t counters, uint32_t tag)
855✔
6034
{
6035
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
855✔
6036
   vcode_add_arg(op, counters);
855✔
6037
   op->tag = tag;
855✔
6038

6039
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
855✔
6040
                "counters argument must be pointer");
6041
}
855✔
6042

6043
void emit_unreachable(vcode_reg_t locus)
1,381✔
6044
{
6045
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
1,381✔
6046
   if (locus != VCODE_INVALID_REG)
1,381✔
6047
      vcode_add_arg(op, locus);
121✔
6048
}
1,381✔
6049

6050
vcode_reg_t emit_undefined(vcode_type_t type, vcode_stamp_t stamp)
63✔
6051
{
6052
   active_unit->flags |= UNIT_UNDEFINED;
63✔
6053

6054
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
63✔
6055
   op->result = vcode_add_reg(type, stamp);
63✔
6056

6057
   return op->result;
63✔
6058
}
6059

6060
void emit_debug_info(const loc_t *loc)
2,473,568✔
6061
{
6062
   if (!loc_invalid_p(loc))
2,473,568✔
6063
      vcode_block_data()->last_loc = *loc;
2,451,371✔
6064
}
2,473,568✔
6065

6066
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
8,872✔
6067
{
6068
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
311,100✔
6069
      if (other->args.items[0] == context && other->ident == name)
12,163✔
6070
         return other->result;
3,992✔
6071
   }
6072

6073
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
4,880✔
6074
   vcode_add_arg(op, context);
4,880✔
6075
   op->ident = name;
4,880✔
6076

6077
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
4,880✔
6078
                "first argument to link var must be context");
6079

6080
   vcode_stamp_t stamp = VCODE_INVALID_STAMP;
4,880✔
6081

6082
   if (vtype_kind(type) == VCODE_TYPE_CARRAY)
4,880✔
6083
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)), stamp);
607✔
6084
   else
6085
      op->result = vcode_add_reg(vtype_pointer(type), stamp);
4,273✔
6086

6087
   return op->result;
4,880✔
6088
}
6089

6090
vcode_reg_t emit_link_package(ident_t name)
12,966✔
6091
{
6092
   VCODE_FOR_EACH_OP(other) {
466,817✔
6093
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
460,083✔
6094
         return other->result;
5,687✔
6095
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
454,396✔
6096
         return other->result;
545✔
6097
   }
6098

6099
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
6,734✔
6100
   op->ident = name;
6,734✔
6101

6102
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
6,734✔
6103

6104
   vcode_type_t type = vtype_context(name);
6,734✔
6105
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
6,734✔
6106
}
6107

6108
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
849✔
6109
{
6110
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
2,046✔
UNCOV
6111
      if (other->args.items[0] == state)
×
6112
         return;
6113
   }
6114

6115
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
849✔
6116
   vcode_add_arg(op, state);
849✔
6117
   if (strong != VCODE_INVALID_REG)
849✔
6118
      vcode_add_arg(op, strong);
36✔
6119

6120
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
849✔
6121
                "state must have integer type");
6122
   VCODE_ASSERT(strong == VCODE_INVALID_REG
849✔
6123
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
6124
                "strong argument not is not boolean");
6125
}
6126

6127
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
48✔
6128
                               vcode_reg_t locus, vcode_reg_t bounds)
6129
{
6130
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
48✔
6131
   vcode_add_arg(op, value);
48✔
6132
   vcode_add_arg(op, context);
48✔
6133
   vcode_add_arg(op, locus);
48✔
6134
   if (bounds != VCODE_INVALID_REG)
48✔
6135
      vcode_add_arg(op, bounds);
6✔
6136

6137
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
48✔
6138
                "invalid reflect value context argument");
6139
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
48✔
6140
                "locus argument to reflect value must be a debug locus");
6141

6142
   vcode_type_t type = vtype_access(vtype_opaque());
48✔
6143
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
48✔
6144
}
6145

6146
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
42✔
6147
                                 vcode_reg_t bounds)
6148
{
6149
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
6150
   vcode_add_arg(op, context);
42✔
6151
   vcode_add_arg(op, locus);
42✔
6152
   if (bounds != VCODE_INVALID_REG)
42✔
UNCOV
6153
      vcode_add_arg(op, bounds);
×
6154

6155
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
6156
                "invalid reflect value context argument");
6157
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
6158
                "locus argument to reflect value must be a debug locus");
6159

6160
   vcode_type_t type = vtype_access(vtype_opaque());
42✔
6161
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
42✔
6162
}
6163

6164
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
202✔
6165
                                  int nargs)
6166
{
6167
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
202✔
6168
   op->func = func;
202✔
6169

6170
   for (int i = 0; i < nargs; i++)
489✔
6171
      vcode_add_arg(op, args[i]);
287✔
6172

6173
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
202✔
6174
}
6175

6176
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
34✔
6177
{
6178
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
34✔
6179
   vcode_add_arg(op, left);
34✔
6180
   vcode_add_arg(op, right);
34✔
6181

6182
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
34✔
6183
                "or trigger left argument must be trigger");
6184
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
34✔
6185
                "or trigger right argument must be trigger");
6186

6187
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
34✔
6188
}
6189

6190
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
65✔
6191
{
6192
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
65✔
6193
   vcode_add_arg(op, left);
65✔
6194
   vcode_add_arg(op, right);
65✔
6195

6196
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
65✔
6197
                "cmp trigger left argument must be signal");
6198
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
65✔
6199
                "cmp trigger right argument must be integer");
6200

6201
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
65✔
6202
}
6203

6204
void emit_add_trigger(vcode_reg_t trigger)
368✔
6205
{
6206
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
368✔
6207
   vcode_add_arg(op, trigger);
368✔
6208

6209
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
368✔
6210
                "add trigger argument must be trigger");
6211
}
368✔
6212

6213
vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective)
204✔
6214
{
6215
   op_t *op = vcode_add_op(VCODE_OP_PORT_CONVERSION);
204✔
6216
   vcode_add_arg(op, driving);
204✔
6217
   if (effective != VCODE_INVALID_REG && effective != driving)
204✔
6218
      vcode_add_arg(op, effective);
18✔
6219

6220
   VCODE_ASSERT(vcode_reg_kind(driving) == VCODE_TYPE_CLOSURE,
204✔
6221
                "port conversion argument must be a closure");
6222
   VCODE_ASSERT(effective == VCODE_INVALID_REG
204✔
6223
                || vcode_reg_kind(effective) == VCODE_TYPE_CLOSURE,
6224
                "port conversion argument must be a closure");
6225

6226
   return (op->result = vcode_add_reg(vtype_conversion(), VCODE_INVALID_STAMP));
204✔
6227
}
6228

6229
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
180✔
6230
                               vcode_type_t type, vcode_stamp_t stamp,
6231
                               const vcode_reg_t *args, int nargs)
6232
{
6233
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
180✔
6234
   op->type  = type;
180✔
6235
   op->ident = scope;
180✔
6236
   vcode_add_arg(op, locus);
180✔
6237
   for (int i = 0; i < nargs; i++)
210✔
6238
      vcode_add_arg(op, args[i]);
30✔
6239

6240
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
180✔
6241
                "bind external argument must be locus");
6242

6243
   op->result = vcode_add_reg(vtype_pointer(type), VCODE_INVALID_STAMP);
180✔
6244
   vcode_reg_data(op->result)->stamp = stamp;
180✔
6245
   return op->result;
180✔
6246
}
6247

6248
void emit_put_conversion(vcode_reg_t cf, vcode_reg_t target, vcode_reg_t count,
342✔
6249
                         vcode_reg_t values)
6250
{
6251
   op_t *op = vcode_add_op(VCODE_OP_PUT_CONVERSION);
342✔
6252
   vcode_add_arg(op, cf);
342✔
6253
   vcode_add_arg(op, target);
342✔
6254
   vcode_add_arg(op, count);
342✔
6255
   vcode_add_arg(op, values);
342✔
6256

6257
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
342✔
6258
                "put conversion target is not signal");
6259
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
342✔
6260
                "put conversion net count is not offset type");
6261
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
342✔
6262
                "signal cannot be values argument for put conversion");
6263
   VCODE_ASSERT(vcode_reg_kind(cf) == VCODE_TYPE_CONVERSION,
342✔
6264
                "cf argument to put conversion must be conversion function");
6265
}
342✔
6266

6267
void emit_convert_in(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
282✔
6268
{
6269
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_IN);
282✔
6270
   vcode_add_arg(op, conv);
282✔
6271
   vcode_add_arg(op, nets);
282✔
6272
   vcode_add_arg(op, count);
282✔
6273

6274
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
282✔
6275
                "conv argument to convert must be a port conversion");
6276
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
282✔
6277
                "nets argument to convert must be a signal");
6278
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
282✔
6279
                "count argument to convert must be offset");
6280
}
282✔
6281

6282
void emit_convert_out(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
324✔
6283
{
6284
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_OUT);
324✔
6285
   vcode_add_arg(op, conv);
324✔
6286
   vcode_add_arg(op, nets);
324✔
6287
   vcode_add_arg(op, count);
324✔
6288

6289
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
324✔
6290
                "conv argument to convert must be a port conversion");
6291
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
324✔
6292
                "nets argument to convert must be a signal");
6293
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
324✔
6294
                "count argument to convert must be offset");
6295
}
324✔
6296

6297
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
1,029✔
6298
{
6299
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
1,029✔
6300
   vcode_add_arg(op, spec);
1,029✔
6301
   vcode_add_arg(op, length);
1,029✔
6302
   if (locus != VCODE_INVALID_REG)
1,029✔
6303
      vcode_add_arg(op, locus);
852✔
6304

6305
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
1,029✔
6306
                "spec argument to bind foreign must be a pointer");
6307
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
1,029✔
6308
                "length argument to bind foreign must be offset");
6309
   VCODE_ASSERT(locus == VCODE_INVALID_REG
1,029✔
6310
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6311
                "locus argument to bind foreign value must be a debug locus");
6312
}
1,029✔
6313

6314
vcode_reg_t emit_instance_name(vcode_reg_t kind)
767✔
6315
{
6316
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
767✔
6317
   vcode_add_arg(op, kind);
767✔
6318

6319
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
767✔
6320
                "kind argument to instance name must be offset");
6321

6322
   vcode_type_t type = vtype_uarray(1, vtype_char());
767✔
6323
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
767✔
6324
}
6325

6326
vcode_reg_t emit_get_counters(ident_t block)
679✔
6327
{
6328
   op_t *op = vcode_add_op(VCODE_OP_GET_COUNTERS);
679✔
6329
   op->ident = block;
679✔
6330

6331
   vcode_type_t vint32 = vtype_int(INT32_MIN, INT32_MAX);
679✔
6332
   vcode_type_t type = vtype_pointer(vint32);
679✔
6333
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
679✔
6334
}
6335

6336
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
10,729✔
6337
{
6338
   vcode_state_t state;
10,729✔
6339
   vcode_state_save(&state);
10,729✔
6340

6341
   vcode_select_unit(vu);
10,729✔
6342

6343
   const int nblocks = vcode_count_blocks();
10,729✔
6344
   for (int i = 0; i < nblocks; i++) {
26,705✔
6345
      vcode_select_block(i);
15,976✔
6346

6347
      const int nops = vcode_count_ops();
15,976✔
6348
      for (int op = 0; op < nops; op++) {
311,126✔
6349
         switch (vcode_get_op(op)) {
295,150✔
6350
         case VCODE_OP_LINK_PACKAGE:
374✔
6351
            (*fn)(vcode_get_ident(op), ctx);
374✔
6352
            break;
374✔
6353
         case VCODE_OP_FCALL:
11,643✔
6354
         case VCODE_OP_PCALL:
6355
         case VCODE_OP_CLOSURE:
6356
         case VCODE_OP_PROTECTED_INIT:
6357
         case VCODE_OP_PACKAGE_INIT:
6358
         case VCODE_OP_FUNCTION_TRIGGER:
6359
            (*fn)(vcode_get_func(op), ctx);
11,643✔
6360
            break;
11,643✔
6361
         default:
6362
            break;
6363
         }
6364
      }
6365
   }
6366

6367
   vcode_state_restore(&state);
10,729✔
6368
}
10,729✔
6369

6370
#if VCODE_CHECK_UNIONS
6371
#define OP_USE_COUNT_U0(x)                                              \
6372
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6373
#define OP_USE_COUNT_U1(x)                                              \
6374
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6375
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6376
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6377

6378
__attribute__((constructor))
6379
static void vcode_check_unions(void)
6380
{
6381
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6382
   for (int i = 0; i < 256; i++) {
6383
      assert(OP_USE_COUNT_U0(i) <= 1);
6384
      assert(OP_USE_COUNT_U1(i) <= 1);
6385
   }
6386
}
6387
#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