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

nickg / nvc / 20645692657

01 Jan 2026 09:14PM UTC coverage: 92.653% (+0.08%) from 92.573%
20645692657

push

github

nickg
Allocate virtual registers in MIR

Fixes #1259

160 of 161 new or added lines in 9 files covered. (99.38%)

579 existing lines in 12 files now uncovered.

76033 of 82062 relevant lines covered (92.65%)

466822.97 hits per line

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

97.15
/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,036,190✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_block);
345,098✔
38
DECLARE_AND_DEFINE_ARRAY(vcode_type);
80,308✔
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
#define OP_HAS_OBJECT(x)                                                 \
58
   (x == VCODE_OP_DEBUG_LOCUS)
59
#define OP_HAS_REAL(x)                                                  \
60
   (x == VCODE_OP_CONST_REAL)
61
#define OP_HAS_VALUE(x)                                                 \
62
   (x == VCODE_OP_CONST || x == VCODE_OP_CONST_REP)
63
#define OP_HAS_DIM(x)                                                   \
64
   (x == VCODE_OP_UARRAY_LEFT || x == VCODE_OP_UARRAY_RIGHT             \
65
    || x == VCODE_OP_UARRAY_DIR || x == VCODE_OP_UARRAY_LEN)
66
#define OP_HAS_HOPS(x)                                                  \
67
   (x == VCODE_OP_VAR_UPREF || x == VCODE_OP_CONTEXT_UPREF)
68
#define OP_HAS_FIELD(x)                                                 \
69
   (x == VCODE_OP_RECORD_REF)
70
#define OP_HAS_CMP(x)                                                   \
71
   (x == VCODE_OP_CMP)
72
#define OP_HAS_TAG(x)                                                   \
73
   (x == VCODE_OP_COVER_STMT || x == VCODE_OP_COVER_BRANCH              \
74
    || x == VCODE_OP_COVER_TOGGLE || x == VCODE_OP_COVER_EXPR           \
75
    || x == VCODE_OP_COVER_STATE)
76
#define OP_HAS_COMMENT(x)                                               \
77
   (x == VCODE_OP_COMMENT)
78
#define OP_HAS_TARGET(x)                                                \
79
   (x == VCODE_OP_WAIT || x == VCODE_OP_JUMP || x == VCODE_OP_COND      \
80
    || x == VCODE_OP_PCALL || x == VCODE_OP_CASE)
81

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

107
DECLARE_AND_DEFINE_ARRAY(op);
11,865,551✔
108

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

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

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

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

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

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

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

178
DECLARE_AND_DEFINE_ARRAY(param);
31,710✔
179
DECLARE_AND_DEFINE_ARRAY(var);
441,418✔
180
DECLARE_AND_DEFINE_ARRAY(reg);
8,711,684✔
181
DECLARE_AND_DEFINE_ARRAY(block);
137,719✔
182
DECLARE_AND_DEFINE_ARRAY(vtype);
21,639,224✔
183
DECLARE_AND_DEFINE_ARRAY(vstamp);
1,413,958✔
184

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

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

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

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

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

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

233
#define VCODE_CHECK_UNIONS 0
234

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

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

244
   return result;
245
}
246

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

253
   return result;
254
}
255

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

262
   return result;
263
}
264

265
static vcode_reg_t vcode_add_reg(vcode_type_t type, vcode_stamp_t stamp)
1,448,248✔
266
{
267
   assert(active_unit != NULL);
1,448,248✔
268

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

275
   return reg;
1,448,248✔
276
}
277

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

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

290
   VCODE_ASSERT(
1,860,925✔
291
      !vcode_block_finished(),
292
      "attempt to add to already finished block %d", active_block);
293

294
   block_t *block = vcode_block_data();
1,860,925✔
295

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

302
   return op;
1,860,925✔
303
}
304

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

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

315
static op_t *vcode_op_data(int op)
10,004,626✔
316
{
317
   assert(active_unit != NULL);
10,004,626✔
318
   assert(active_block != VCODE_INVALID_BLOCK);
10,004,626✔
319

320
   block_t *b = &(active_unit->blocks.items[active_block]);
10,004,626✔
321
   return op_array_nth_ptr(&(b->ops), op);
10,004,626✔
322
}
323

324
static op_t *vcode_find_definition(vcode_reg_t reg)
1,673,114✔
325
{
326
   for (int i = active_block; i >= 0; i--) {
1,704,430✔
327
      block_t *b = &(active_unit->blocks.items[i]);
1,703,034✔
328
      for (int j = b->ops.count - 1; j >= 0; j--) {
33,216,915✔
329
         if (b->ops.items[j].result == reg)
33,185,599✔
330
            return &(b->ops.items[j]);
1,671,718✔
331
      }
332
   }
333

334
   return NULL;
335
}
336

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

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

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

367
   int depth = MASK_CONTEXT(type);
5,600,176✔
368
   assert(depth <= unit->depth);
5,600,176✔
369
   while (depth != unit->depth)
6,464,909✔
370
      unit = unit->context;
864,733✔
371

372
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
5,600,176✔
373
}
374

375
static vstamp_t *vcode_stamp_data(vcode_stamp_t stamp)
1,154,631✔
376
{
377
   if (stamp == VCODE_INVALID_STAMP)
1,154,631✔
378
      return NULL;
379

380
   assert(active_unit != NULL);
1,077,044✔
381
   vcode_unit_t unit = active_unit;
1,077,044✔
382

383
   int depth = MASK_CONTEXT(stamp);
1,077,044✔
384
   assert(depth <= unit->depth);
1,077,044✔
385
   while (depth != unit->depth)
1,105,893✔
386
      unit = unit->context;
28,849✔
387

388
   return vstamp_array_nth_ptr(&(unit->stamps), MASK_INDEX(stamp));
1,077,044✔
389
}
390

391
static var_t *vcode_var_data(vcode_var_t var)
370,753✔
392
{
393
   assert(active_unit != NULL);
370,753✔
394
   assert(var != VCODE_INVALID_VAR);
370,753✔
395

396
   return var_array_nth_ptr(&(active_unit->vars), var);
370,753✔
397
}
398

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

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

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

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

432
   case VCODE_OP_VAR_UPREF:
640✔
433
      {
434
         vcode_unit_t vu = vcode_active_unit();
640✔
435
         for (int i = 0; i < defn->hops; i++)
1,286✔
436
            vu = vcode_unit_context(vu);
646✔
437

438
         vcode_state_t state;
640✔
439
         vcode_state_save(&state);
640✔
440

441
         vcode_select_unit(vu);
640✔
442

443
         vcode_var_data(defn->address)->flags |= VAR_HEAP;
640✔
444

445
         vcode_state_restore(&state);
640✔
446
      }
447
      break;
640✔
448

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

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

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

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

468
         // Any store to this variable must be heap allocated
469
         for (int i = 0; i < active_unit->blocks.count; i++) {
18,398✔
470
            block_t *b = &(active_unit->blocks.items[i]);
17,268✔
471
            for (int j = 0; j < b->ops.count; j++) {
237,421✔
472
               op_t *op = &(b->ops.items[j]);
220,153✔
473
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
220,153✔
474
                  vcode_heap_allocate(op->args.items[0]);
1,130✔
475

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

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

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

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

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

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

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

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

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

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

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

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

574
   if (unit == active_unit)
50,790✔
575
      vcode_close();
11,166✔
576

577
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
65,137✔
578
      assert(it->context == unit);
14,347✔
579
      it->context = NULL;
14,347✔
580
   }
581
   unit->children = NULL;
50,790✔
582

583
   if (unit->context != NULL) {
50,790✔
584
      vcode_unit_t *it = &(unit->context->children);
13,295✔
585
      for (; *it != NULL && *it != unit; it = &((*it)->next))
36,112✔
586
         ;
587
      assert(*it != NULL);
13,295✔
588
      *it = (*it)->next;
13,295✔
589
   }
590

591
   for (unsigned i = 0; i < unit->blocks.count; i++) {
188,411✔
592
      block_t *b = &(unit->blocks.items[i]);
137,621✔
593

594
      for (unsigned j = 0; j < b->ops.count; j++) {
1,916,465✔
595
         op_t *o = &(b->ops.items[j]);
1,778,844✔
596
         if (OP_HAS_COMMENT(o->kind))
1,778,844✔
597
            free(o->comment);
196,622✔
598
         if (OP_HAS_TARGET(o->kind))
1,778,844✔
599
            free(o->targets.items);
81,084✔
600
         free(o->args.items);
1,778,844✔
601
      }
602
      free(b->ops.items);
137,621✔
603
   }
604
   free(unit->blocks.items);
50,790✔
605

606
   for (unsigned i = 0; i < unit->types.count; i++) {
379,207✔
607
      vtype_t *vt = &(unit->types.items[i]);
328,417✔
608
      if (vt->kind == VCODE_TYPE_RECORD)
328,417✔
609
         free(vt->fields.items);
5,706✔
610
   }
611
   free(unit->types.items);
50,790✔
612

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

620
vcode_unit_t vcode_unit_next(vcode_unit_t unit)
16,252✔
621
{
622
   return unit->next;
16,252✔
623
}
624

625
vcode_unit_t vcode_unit_child(vcode_unit_t unit)
15,360✔
626
{
627
   return unit->children;
15,360✔
628
}
629

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

636
vcode_type_t vcode_reg_type(vcode_reg_t reg)
5,461,717✔
637
{
638
   return vcode_reg_data(reg)->type;
5,461,717✔
639
}
640

641
vtype_kind_t vcode_reg_kind(vcode_reg_t reg)
1,334,817✔
642
{
643
   return vtype_kind(vcode_reg_type(reg));
1,334,817✔
644
}
645

646
vcode_stamp_t vcode_reg_stamp(vcode_reg_t reg)
225,520✔
647
{
648
   return vcode_reg_data(reg)->stamp;
225,520✔
649
}
650

651
bool vcode_reg_const(vcode_reg_t reg, int64_t *value)
870,136✔
652
{
653
   reg_t *r = vcode_reg_data(reg);
870,136✔
654

655
   if (r->stamp == VCODE_INVALID_STAMP)
870,136✔
656
      return false;
657

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

660
   if (s->kind != VCODE_STAMP_INT)
656,269✔
661
      return false;
662

663
   if (s->u.intg.low == s->u.intg.high) {
630,126✔
664
      if (value) *value = s->u.intg.low;
472,052✔
665
      return true;
472,052✔
666
   }
667
   else
668
      return false;
669
}
670

671
bool vcode_reg_bounds(vcode_reg_t reg, int64_t *low, int64_t *high)
387,385✔
672
{
673
   reg_t *r = vcode_reg_data(reg);
387,385✔
674
   if (r->stamp == VCODE_INVALID_STAMP) {
387,385✔
675
      vtype_t *t = vcode_type_data(r->type);
74,716✔
676
      if (t->kind == VCODE_TYPE_INT || t->kind == VCODE_TYPE_OFFSET) {
74,716✔
677
         *low = t->low;
73,652✔
678
         *high = t->high;
73,652✔
679
         return true;
73,652✔
680
      }
681
   }
682
   else {
683
      vstamp_t *s = vcode_stamp_data(r->stamp);
312,669✔
684
      if (s->kind == VCODE_STAMP_INT) {
312,669✔
685
         *low = s->u.intg.low;
312,235✔
686
         *high = s->u.intg.high;
312,235✔
687
         return true;
312,235✔
688
      }
689
   }
690

691
   return false;
692
}
693

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

714
   return false;
715
}
716

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

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

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

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

731
         for (int j = b->ops.count - 1; j >= 0; j--) {
3,531,529✔
732
            op_t *o = &(b->ops.items[j]);
3,303,554✔
733

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

796
            default:
797
               break;
798
            }
799

800
            for (int k = 0; k < o->args.count; k++) {
9,334,763✔
801
               if (o->args.items[k] != VCODE_INVALID_REG)
6,031,209✔
802
                  uses[o->args.items[k]]++;
5,995,603✔
803
            }
804
         }
805
      }
806
   } while (pruned > 0);
72,974✔
807

808
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
188,535✔
809
      block_t *b = &(active_unit->blocks.items[i]);
137,719✔
810
      op_t *dst = &(b->ops.items[0]);
137,719✔
811
      size_t copied = 0;
137,719✔
812
      for (int j = 0; j < b->ops.count; j++) {
1,998,644✔
813
         const op_t *src = &(b->ops.items[j]);
1,860,925✔
814
         if (src->kind != (vcode_op_t)-1) {
1,860,925✔
815
            if (src != dst) {
1,779,734✔
816
               assert(dst < src);
584,406✔
817
               *dst = *src;
584,406✔
818
            }
819
            dst++;
1,779,734✔
820
            copied++;
1,779,734✔
821
         }
822
      }
823

824
      assert(copied <= b->ops.count);
137,719✔
825
      b->ops.count = copied;
137,719✔
826
   }
827
}
50,816✔
828

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

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

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

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

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

862
   return VCODE_INVALID_VAR;
863
}
864

865
ident_t vcode_var_name(vcode_var_t var)
75,092✔
866
{
867
   return vcode_var_data(var)->name;
75,092✔
868
}
869

870
vcode_type_t vcode_var_type(vcode_var_t var)
75,822✔
871
{
872
   return vcode_var_data(var)->type;
75,822✔
873
}
874

875
vcode_var_flags_t vcode_var_flags(vcode_var_t var)
77,191✔
876
{
877
   return vcode_var_data(var)->flags;
77,191✔
878
}
879

880
vcode_op_t vcode_get_op(int op)
2,396,038✔
881
{
882
   return vcode_op_data(op)->kind;
2,396,038✔
883
}
884

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

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

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

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

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

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

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

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

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

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

955
int vcode_count_args(int op)
244,984✔
956
{
957
   return vcode_op_data(op)->args.count;
244,984✔
958
}
959

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

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

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

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

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

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

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

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

1007
bool vcode_block_finished(void)
1,977,179✔
1008
{
1009
   assert(active_unit != NULL);
1,977,179✔
1010
   assert(active_block != VCODE_INVALID_BLOCK);
1,977,179✔
1011

1012
   const block_t *b = &(active_unit->blocks.items[active_block]);
1,977,179✔
1013
   if (b->ops.count == 0)
1,977,179✔
1014
      return false;
1015
   else {
1016
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,791,145✔
1017
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,791,145✔
1018
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,791,127✔
1019
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
1020
         || kind == VCODE_OP_UNREACHABLE;
3,582,272✔
1021
   }
1022
}
1023

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

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

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

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

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

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

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

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

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

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

1143
   case VCODE_TYPE_OFFSET:
1144
      col += printf("#");
1145
      break;
1146

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

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

1157
   case VCODE_TYPE_OPAQUE:
1158
      col += printf("?");
1159
      break;
1160

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

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

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

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

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

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

1190
   return col;
1191
}
1192

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

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

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

1214
   if (stamp == VCODE_INVALID_STAMP)
1215
      return;
1216

1217
   printf(" => ");
1218

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

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

1238
   default:
1239
      should_not_reach_here();
1240
   }
1241
}
1242

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

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

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

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

1269
   const vcode_unit_t vu = active_unit;
1270
   vcode_block_t old_block = active_block;
1271

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2143
         case VCODE_OP_ALL:
2144
            {
2145
               col += vcode_dump_reg(op->result);
2146
               col += printf(" := %s ", vcode_op_string(op->kind));
2147
               col += vcode_dump_reg(op->args.items[0]);
2148
               vcode_dump_result_type(col, op);
2149
            }
2150
            break;
2151

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

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

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

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

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

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

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

2239
         case VCODE_OP_COVER_STMT:
2240
         case VCODE_OP_COVER_BRANCH:
2241
         case VCODE_OP_COVER_EXPR:
2242
            {
2243
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2244
            }
2245
            break;
2246

2247
         case VCODE_OP_COVER_TOGGLE:
2248
         case VCODE_OP_COVER_STATE:
2249
            {
2250
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2251
               vcode_dump_reg(op->args.items[0]);
2252
            }
2253
            break;
2254

2255
         case VCODE_OP_UNDEFINED:
2256
            {
2257
               col += vcode_dump_reg(op->result);
2258
               col += printf(" := %s", vcode_op_string(op->kind));
2259
               vcode_dump_result_type(col, op);
2260
            }
2261
            break;
2262

2263
         case VCODE_OP_RANGE_LENGTH:
2264
         case VCODE_OP_RANGE_NULL:
2265
            {
2266
               col += vcode_dump_reg(op->result);
2267
               col += printf(" := %s left ", vcode_op_string(op->kind));
2268
               vcode_dump_reg(op->args.items[0]);
2269
               col += printf(" right ");
2270
               vcode_dump_reg(op->args.items[1]);
2271
               col += printf(" dir ");
2272
               col += vcode_dump_reg(op->args.items[2]);
2273
               vcode_dump_result_type(col, op);
2274
            }
2275
            break;
2276

2277
         case VCODE_OP_LINK_PACKAGE:
2278
            {
2279
               col += vcode_dump_reg(op->result);
2280
               col += nvc_printf(" := %s $magenta$%s$$",
2281
                                 vcode_op_string(op->kind), istr(op->ident));
2282
               if (op->args.count > 0) {
2283
                  col += printf(" locus ");
2284
                  col += vcode_dump_reg(op->args.items[0]);
2285
               }
2286
               vcode_dump_result_type(col, op);
2287
            }
2288
            break;
2289

2290
         case VCODE_OP_LINK_VAR:
2291
            {
2292
               col += vcode_dump_reg(op->result);
2293
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
2294
               col += vcode_dump_reg(op->args.items[0]);
2295
               col += nvc_printf(" $magenta$%s$$", istr(op->ident));
2296
               vcode_dump_result_type(col, op);
2297
            }
2298
            break;
2299

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

2310
         case VCODE_OP_DEBUG_LOCUS:
2311
            {
2312
               col += vcode_dump_reg(op->result);
2313
               col += nvc_printf(" := %s $magenta$", vcode_op_string(op->kind));
2314

2315
               tree_t t = tree_from_object(op->object);
2316
               if (t != NULL)
2317
                  col += printf("%s@", tree_kind_str(tree_kind(t)));
2318

2319
               col += nvc_printf("%p$$", op->object);
2320
               vcode_dump_result_type(col, op);
2321
            }
2322
            break;
2323

2324
         case VCODE_OP_ENTER_STATE:
2325
            {
2326
               printf("%s ", vcode_op_string(op->kind));
2327
               vcode_dump_reg(op->args.items[0]);
2328
               if (op->args.count > 1) {
2329
                  printf(" strong ");
2330
                  vcode_dump_reg(op->args.items[1]);
2331
               }
2332
            }
2333
            break;
2334

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

2352
         case VCODE_OP_REFLECT_SUBTYPE:
2353
            {
2354
               col += vcode_dump_reg(op->result);
2355
               col += printf(" := %s context ", vcode_op_string(op->kind));
2356
               vcode_dump_reg(op->args.items[0]);
2357
               col += printf(" locus ");
2358
               col += vcode_dump_reg(op->args.items[1]);
2359
               if (op->args.count > 2) {
2360
                  col += printf(" bounds ");
2361
                  col += vcode_dump_reg(op->args.items[2]);
2362
               }
2363
               vcode_dump_result_type(col, op);
2364
            }
2365
            break;
2366

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

2380
         case VCODE_OP_OR_TRIGGER:
2381
         case VCODE_OP_CMP_TRIGGER:
2382
            {
2383
               col += vcode_dump_reg(op->result);
2384
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
2385
               col += vcode_dump_reg(op->args.items[0]);
2386
               if (op->kind == VCODE_OP_OR_TRIGGER)
2387
                  col += printf(" || ");
2388
               else
2389
                  col += printf(" == ");
2390
               col += vcode_dump_reg(op->args.items[1]);
2391
               vcode_dump_result_type(col, op);
2392
            }
2393
            break;
2394

2395
         case VCODE_OP_ADD_TRIGGER:
2396
            {
2397
               printf("%s ", vcode_op_string(op->kind));
2398
               vcode_dump_reg(op->args.items[0]);
2399
            }
2400
            break;
2401

2402
         case VCODE_OP_PUT_CONVERSION:
2403
            {
2404
               nvc_printf("%s ", vcode_op_string(op->kind));
2405
               vcode_dump_reg(op->args.items[0]);
2406
               printf(" signal ");
2407
               vcode_dump_reg(op->args.items[1]);
2408
               printf(" count ");
2409
               vcode_dump_reg(op->args.items[2]);
2410
               printf(" values ");
2411
               vcode_dump_reg(op->args.items[3]);
2412
            }
2413
            break;
2414

2415
         case VCODE_OP_PORT_CONVERSION:
2416
            {
2417
               col += vcode_dump_reg(op->result);
2418
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
2419
               col += vcode_dump_reg(op->args.items[0]);
2420
               if (op->args.count > 1) {
2421
                  col += printf(" effective ");
2422
                  col += vcode_dump_reg(op->args.items[1]);
2423
               }
2424
               vcode_dump_result_type(col, op);
2425
            }
2426
            break;
2427

2428
         case VCODE_OP_CONVERT_IN:
2429
         case VCODE_OP_CONVERT_OUT:
2430
            {
2431
               nvc_printf("%s ", vcode_op_string(op->kind));
2432
               vcode_dump_reg(op->args.items[0]);
2433
               printf(" signal ");
2434
               vcode_dump_reg(op->args.items[1]);
2435
               printf(" count ");
2436
               vcode_dump_reg(op->args.items[2]);
2437
            }
2438
            break;
2439

2440
         case VCODE_OP_BIND_FOREIGN:
2441
            {
2442
               nvc_printf("%s ", vcode_op_string(op->kind));
2443
               vcode_dump_reg(op->args.items[0]);
2444
               printf(" length ");
2445
               vcode_dump_reg(op->args.items[1]);
2446
               if (op->args.count > 2) {
2447
                  printf(" locus ");
2448
                  vcode_dump_reg(op->args.items[1]);
2449
               }
2450
            }
2451
            break;
2452

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

2469
         if (j == mark_op && i == old_block)
2470
            nvc_printf("\t $red$<----$$");
2471

2472
         nvc_printf("$$\n");
2473

2474
         if (callback != NULL)
2475
            (*callback)(j, arg);
2476
      }
2477

2478
      if (b->ops.count == 0)
2479
         nvc_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2480
   }
2481

2482
   printf("\n");
2483
   fflush(stdout);
2484

2485
   active_block = old_block;
2486
}
2487
LCOV_EXCL_STOP
2488

2489
static inline bool vtype_eq_internal(const vtype_t *at, const vtype_t *bt)
13,788,544✔
2490
{
2491
   if (at->kind != bt->kind)
13,788,544✔
2492
      return false;
2493

2494
   switch (at->kind) {
3,697,115✔
2495
   case VCODE_TYPE_INT:
2,457,118✔
2496
      return (at->low == bt->low) && (at->high == bt->high);
3,582,991✔
2497
   case VCODE_TYPE_REAL:
55,699✔
2498
      return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
55,745✔
2499
   case VCODE_TYPE_CARRAY:
102,519✔
2500
      return at->size == bt->size && vtype_eq(at->elem, bt->elem);
109,834✔
2501
   case VCODE_TYPE_UARRAY:
79,620✔
2502
      return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
99,779✔
2503
   case VCODE_TYPE_POINTER:
473,174✔
2504
   case VCODE_TYPE_ACCESS:
2505
      return vtype_eq(at->pointed, bt->pointed);
473,174✔
2506
   case VCODE_TYPE_OFFSET:
2507
   case VCODE_TYPE_OPAQUE:
2508
   case VCODE_TYPE_DEBUG_LOCUS:
2509
   case VCODE_TYPE_TRIGGER:
2510
   case VCODE_TYPE_CONVERSION:
2511
      return true;
2512
   case VCODE_TYPE_RESOLUTION:
73,582✔
2513
   case VCODE_TYPE_CLOSURE:
2514
   case VCODE_TYPE_SIGNAL:
2515
   case VCODE_TYPE_FILE:
2516
      return vtype_eq(at->base, bt->base);
73,582✔
2517
   case VCODE_TYPE_RECORD:
55,747✔
2518
   case VCODE_TYPE_CONTEXT:
2519
      return at->name == bt->name;
55,747✔
UNCOV
2520
   default:
×
2521
      should_not_reach_here();
2522
   }
2523
}
2524

2525
bool vtype_eq(vcode_type_t a, vcode_type_t b)
4,562,914✔
2526
{
2527
   assert(active_unit != NULL);
4,562,914✔
2528

2529
   if (a == b)
4,562,914✔
2530
      return true;
2531
   else if (MASK_CONTEXT(a) == MASK_CONTEXT(b))
945,106✔
2532
      return false;   // Guaranteed by vtype_new
2533
   else {
2534
      const vtype_t *at = vcode_type_data(a);
118,687✔
2535
      const vtype_t *bt = vcode_type_data(b);
118,687✔
2536

2537
      return vtype_eq_internal(at, bt);
118,687✔
2538
   }
2539
}
2540

UNCOV
2541
void vcode_dump(void)
×
2542
{
UNCOV
2543
   vcode_dump_with_mark(-1, NULL, NULL);
×
UNCOV
2544
}
×
2545

2546
static vcode_type_t vtype_new(vtype_t *new)
2,369,191✔
2547
{
2548
   const int index = active_unit->types.count - 1;
2,369,191✔
2549

2550
   for (int i = 0; i < index; i++) {
13,998,406✔
2551
      const vtype_t *cmp = vtype_array_nth_ptr(&(active_unit->types), i);
13,669,857✔
2552
      if (vtype_eq_internal(new, cmp)) {
13,669,857✔
2553
         active_unit->types.count--;
2,040,642✔
2554
         return MAKE_HANDLE(active_unit->depth, i);
2,040,642✔
2555
      }
2556
   }
2557

2558
   return MAKE_HANDLE(active_unit->depth, index);
328,549✔
2559
}
2560

2561
vcode_type_t vtype_int(int64_t low, int64_t high)
1,396,101✔
2562
{
2563
   assert(active_unit != NULL);
1,396,101✔
2564

2565
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,396,101✔
2566
   n->kind = VCODE_TYPE_INT;
1,396,101✔
2567
   n->low  = low;
1,396,101✔
2568
   n->high = high;
1,396,101✔
2569

2570
   switch (bits_for_range(low, high)) {
1,396,101✔
2571
   case 64:
55,611✔
2572
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
55,611✔
2573
      break;
55,611✔
2574
   case 32:
364,897✔
2575
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
364,897✔
2576
      break;
364,897✔
2577
   case 16:
126✔
2578
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
126✔
2579
      break;
126✔
2580
   case 8:
544,470✔
2581
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
544,470✔
2582
      break;
544,470✔
2583
   case 1:
430,997✔
2584
      n->repr = VCODE_REPR_U1;
430,997✔
2585
      break;
430,997✔
UNCOV
2586
   case 0:
×
UNCOV
2587
      n->repr = VCODE_REPR_I64;    // Null range
×
UNCOV
2588
      break;
×
UNCOV
2589
   default:
×
2590
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2591
   }
2592

2593
   return vtype_new(n);
1,396,101✔
2594
}
2595

2596
vcode_type_t vtype_bool(void)
335,355✔
2597
{
2598
   return vtype_int(0, 1);
335,355✔
2599
}
2600

2601
vcode_type_t vtype_carray(int size, vcode_type_t elem)
55,978✔
2602
{
2603
   assert(active_unit != NULL);
55,978✔
2604

2605
   const vtype_kind_t ekind = vtype_kind(elem);
55,978✔
2606
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
55,978✔
2607
                "array types may not be nested");
2608

2609
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
55,978✔
2610
   memset(n, '\0', sizeof(vtype_t));
55,978✔
2611
   n->kind   = VCODE_TYPE_CARRAY;
55,978✔
2612
   n->elem   = elem;
55,978✔
2613
   n->size   = MAX(size, 0);
55,978✔
2614

2615
   return vtype_new(n);
55,978✔
2616
}
2617

2618
vcode_type_t vtype_find_named_record(ident_t name)
28,932✔
2619
{
2620
   assert(active_unit != NULL);
28,932✔
2621

2622
   for (int i = 0; i < active_unit->types.count; i++) {
260,838✔
2623
      vtype_t *other = &(active_unit->types.items[i]);
249,426✔
2624
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
249,426✔
2625
         return MAKE_HANDLE(active_unit->depth, i);
17,520✔
2626
   }
2627

2628
   return VCODE_INVALID_TYPE;
2629
}
2630

2631
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
11,412✔
2632
                                int nfields)
2633
{
2634
   assert(active_unit != NULL);
11,412✔
2635

2636
   vtype_t *data = NULL;
11,412✔
2637
   vcode_type_t handle = vtype_find_named_record(name);
11,412✔
2638
   if (handle == VCODE_INVALID_TYPE) {
11,412✔
2639
      data = vtype_array_alloc(&(active_unit->types));
5,706✔
2640
      memset(data, '\0', sizeof(vtype_t));
5,706✔
2641
      data->kind = VCODE_TYPE_RECORD;
5,706✔
2642
      data->name = name;
5,706✔
2643

2644
      handle = vtype_new(data);
5,706✔
2645
   }
2646
   else {
2647
      data = vcode_type_data(handle);
5,706✔
2648
      VCODE_ASSERT(data->fields.count == 0,
5,706✔
2649
                    "record type %s already defined", istr(name));
2650
   }
2651

2652
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
11,412✔
2653
   for (int i = 0; i < nfields; i++)
30,366✔
2654
      vcode_type_array_add(&(data->fields), field_types[i]);
18,954✔
2655

2656
   return handle;
11,412✔
2657
}
2658

2659
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem)
76,637✔
2660
{
2661
   assert(active_unit != NULL);
76,637✔
2662

2663
   const vtype_kind_t ekind = vtype_kind(elem);
76,637✔
2664
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
76,637✔
2665
                "array types may not be nested");
2666

2667
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
76,637✔
2668

2669
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
76,637✔
2670
   memset(n, '\0', sizeof(vtype_t));
76,637✔
2671
   n->kind = VCODE_TYPE_UARRAY;
76,637✔
2672
   n->elem = elem;
76,637✔
2673
   n->dims = ndim;
76,637✔
2674

2675
   return vtype_new(n);
76,637✔
2676
}
2677

2678
vcode_type_t vtype_pointer(vcode_type_t to)
202,929✔
2679
{
2680
   assert(active_unit != NULL);
202,929✔
2681

2682
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
202,929✔
2683
   n->kind    = VCODE_TYPE_POINTER;
202,929✔
2684
   n->pointed = to;
202,929✔
2685

2686
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
202,929✔
2687
                "cannot get pointer to carray type");
2688

2689
   return vtype_new(n);
202,929✔
2690
}
2691

2692
vcode_type_t vtype_access(vcode_type_t to)
6,576✔
2693
{
2694
   assert(active_unit != NULL);
6,576✔
2695

2696
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
6,576✔
2697
   n->kind    = VCODE_TYPE_ACCESS;
6,576✔
2698
   n->pointed = to;
6,576✔
2699

2700
   return vtype_new(n);
6,576✔
2701
}
2702

2703
vcode_type_t vtype_signal(vcode_type_t base)
39,540✔
2704
{
2705
   assert(active_unit != NULL);
39,540✔
2706

2707
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
39,540✔
2708
   n->kind = VCODE_TYPE_SIGNAL;
39,540✔
2709
   n->base = base;
39,540✔
2710

2711
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
39,540✔
2712

2713
   return vtype_new(n);
39,540✔
2714
}
2715

2716
vcode_type_t vtype_resolution(vcode_type_t base)
8,323✔
2717
{
2718
   assert(active_unit != NULL);
8,323✔
2719

2720
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
8,323✔
2721
   n->kind = VCODE_TYPE_RESOLUTION;
8,323✔
2722
   n->base = base;
8,323✔
2723

2724
   return vtype_new(n);
8,323✔
2725
}
2726

2727
vcode_type_t vtype_closure(vcode_type_t result)
5,448✔
2728
{
2729
   assert(active_unit != NULL);
5,448✔
2730

2731
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
5,448✔
2732
   n->kind = VCODE_TYPE_CLOSURE;
5,448✔
2733
   n->base = result;
5,448✔
2734

2735
   return vtype_new(n);
5,448✔
2736
}
2737

2738
vcode_type_t vtype_context(ident_t name)
54,152✔
2739
{
2740
   assert(active_unit != NULL);
54,152✔
2741
   assert(name != NULL);
54,152✔
2742

2743
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
54,152✔
2744
   n->kind = VCODE_TYPE_CONTEXT;
54,152✔
2745
   n->name = name;
54,152✔
2746

2747
   return vtype_new(n);
54,152✔
2748
}
2749

2750
vcode_type_t vtype_file(vcode_type_t base)
1,606✔
2751
{
2752
   assert(active_unit != NULL);
1,606✔
2753

2754
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,606✔
2755
   n->kind = VCODE_TYPE_FILE;
1,606✔
2756
   n->base = base;
1,606✔
2757

2758
   return vtype_new(n);
1,606✔
2759
}
2760

2761
vcode_type_t vtype_offset(void)
293,447✔
2762
{
2763
   assert(active_unit != NULL);
293,447✔
2764

2765
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
293,447✔
2766
   n->kind = VCODE_TYPE_OFFSET;
293,447✔
2767
   n->low  = INT64_MIN;
293,447✔
2768
   n->high = INT64_MAX;
293,447✔
2769
   n->repr = VCODE_REPR_I64;
293,447✔
2770

2771
   return vtype_new(n);
293,447✔
2772
}
2773

2774
vcode_type_t vtype_time(void)
14,708✔
2775
{
2776
   return vtype_int(INT64_MIN, INT64_MAX);
14,708✔
2777
}
2778

2779
vcode_type_t vtype_char(void)
8,179✔
2780
{
2781
   return vtype_int(0, 255);
8,179✔
2782
}
2783

2784
vcode_type_t vtype_opaque(void)
2,395✔
2785
{
2786
   assert(active_unit != NULL);
2,395✔
2787

2788
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
2,395✔
2789
   n->kind = VCODE_TYPE_OPAQUE;
2,395✔
2790

2791
   return vtype_new(n);
2,395✔
2792
}
2793

2794
vcode_type_t vtype_debug_locus(void)
156,664✔
2795
{
2796
   assert(active_unit != NULL);
156,664✔
2797

2798
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
156,664✔
2799
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
156,664✔
2800

2801
   return vtype_new(n);
156,664✔
2802
}
2803

2804
vcode_type_t vtype_trigger(void)
386✔
2805
{
2806
   assert(active_unit != NULL);
386✔
2807

2808
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
386✔
2809
   n->kind = VCODE_TYPE_TRIGGER;
386✔
2810

2811
   return vtype_new(n);
386✔
2812
}
2813

2814
vcode_type_t vtype_conversion(void)
426✔
2815
{
2816
   assert(active_unit != NULL);
426✔
2817

2818
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
426✔
2819
   n->kind = VCODE_TYPE_CONVERSION;
426✔
2820

2821
   return vtype_new(n);
426✔
2822
}
2823

2824
vcode_type_t vtype_real(double low, double high)
62,877✔
2825
{
2826
   assert(active_unit != NULL);
62,877✔
2827

2828
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
62,877✔
2829
   n->kind  = VCODE_TYPE_REAL;
62,877✔
2830
   n->rlow  = low;
62,877✔
2831
   n->rhigh = high;
62,877✔
2832

2833
   return vtype_new(n);
62,877✔
2834
}
2835

2836
vtype_kind_t vtype_kind(vcode_type_t type)
3,906,106✔
2837
{
2838
   vtype_t *vt = vcode_type_data(type);
3,906,106✔
2839
   return vt->kind;
3,906,106✔
2840
}
2841

2842
vtype_repr_t vtype_repr(vcode_type_t type)
42,593✔
2843
{
2844
   vtype_t *vt = vcode_type_data(type);
42,593✔
2845
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
42,593✔
2846
   return vt->repr;
42,593✔
2847
}
2848

2849
vcode_type_t vtype_elem(vcode_type_t type)
127,873✔
2850
{
2851
   vtype_t *vt = vcode_type_data(type);
127,873✔
2852
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
127,873✔
2853
   return vt->elem;
127,873✔
2854
}
2855

2856
vcode_type_t vtype_base(vcode_type_t type)
52,730✔
2857
{
2858
   vtype_t *vt = vcode_type_data(type);
52,730✔
2859
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
52,730✔
2860
          || vt->kind == VCODE_TYPE_RESOLUTION
2861
          || vt->kind == VCODE_TYPE_CLOSURE);
2862
   return vt->base;
52,730✔
2863
}
2864

2865
unsigned vtype_dims(vcode_type_t type)
43,238✔
2866
{
2867
   vtype_t *vt = vcode_type_data(type);
43,238✔
2868
   assert(vt->kind == VCODE_TYPE_UARRAY);
43,238✔
2869
   return vt->dims;
43,238✔
2870
}
2871

2872
unsigned vtype_size(vcode_type_t type)
52,617✔
2873
{
2874
   vtype_t *vt = vcode_type_data(type);
52,617✔
2875
   assert(vt->kind == VCODE_TYPE_CARRAY);
52,617✔
2876
   return vt->size;
52,617✔
2877
}
2878

2879
int vtype_fields(vcode_type_t type)
8,021✔
2880
{
2881
   vtype_t *vt = vcode_type_data(type);
8,021✔
2882
   assert(vt->kind == VCODE_TYPE_RECORD);
8,021✔
2883
   return vt->fields.count;
8,021✔
2884
}
2885

2886
vcode_type_t vtype_field(vcode_type_t type, int field)
30,988✔
2887
{
2888
   vtype_t *vt = vcode_type_data(type);
30,988✔
2889
   assert(vt->kind == VCODE_TYPE_RECORD);
30,988✔
2890
   return vcode_type_array_nth(&(vt->fields), field);
30,988✔
2891
}
2892

2893
ident_t vtype_name(vcode_type_t type)
19,097✔
2894
{
2895
   vtype_t *vt = vcode_type_data(type);
19,097✔
2896
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
19,097✔
2897
   return vt->name;
19,097✔
2898
}
2899

2900
vcode_type_t vtype_pointed(vcode_type_t type)
339,185✔
2901
{
2902
   vtype_t *vt = vcode_type_data(type);
339,185✔
2903
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
339,185✔
2904
   return vt->pointed;
339,185✔
2905
}
2906

2907
int64_t vtype_low(vcode_type_t type)
82,798✔
2908
{
2909
   vtype_t *vt = vcode_type_data(type);
82,798✔
2910
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
82,798✔
2911
   return vt->low;
82,798✔
2912
}
2913

2914
int64_t vtype_high(vcode_type_t type)
83,393✔
2915
{
2916
   vtype_t *vt = vcode_type_data(type);
83,393✔
2917
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
83,393✔
2918
   return vt->high;
83,393✔
2919
}
2920

2921
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
1,587✔
2922
{
2923
   return vtype_kind(type) == VCODE_TYPE_POINTER
1,587✔
2924
      && vtype_kind(vtype_pointed(type)) == to;
1,587✔
2925
}
2926

2927
bool vtype_is_scalar(vcode_type_t type)
420,624✔
2928
{
2929
   const vtype_kind_t kind = vtype_kind(type);
420,624✔
2930
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
420,624✔
2931
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
163,041✔
2932
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2933
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2934
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER
2935
      || kind == VCODE_TYPE_RESOLUTION;
420,624✔
2936
}
2937

2938
bool vtype_is_numeric(vcode_type_t type)
18,704✔
2939
{
2940
   const vtype_kind_t kind = vtype_kind(type);
18,704✔
2941
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
18,704✔
2942
      || kind == VCODE_TYPE_REAL;
18,704✔
2943
}
2944

2945
bool vtype_is_integral(vcode_type_t type)
1,046✔
2946
{
2947
   const vtype_kind_t kind = vtype_kind(type);
1,046✔
2948
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET;
1,046✔
2949
}
2950

2951
bool vtype_is_composite(vcode_type_t type)
31,919✔
2952
{
2953
   const vtype_kind_t kind = vtype_kind(type);
31,919✔
2954
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
31,919✔
2955
}
2956

2957
bool vtype_is_signal(vcode_type_t type)
154,012✔
2958
{
2959
   vtype_t *vt = vcode_type_data(type);
275,606✔
2960
   switch (vt->kind) {
275,606✔
2961
   case VCODE_TYPE_SIGNAL:
2962
      return true;
2963
   case VCODE_TYPE_POINTER:
71,644✔
2964
      return vtype_is_signal(vt->pointed);
71,644✔
2965
   case VCODE_TYPE_RECORD:
2966
      for (int i = 0; i < vt->fields.count; i++) {
34,338✔
2967
         if (vtype_is_signal(vt->fields.items[i]))
27,125✔
2968
            return true;
2969
      }
2970
      return false;
2971
   case VCODE_TYPE_UARRAY:
49,950✔
2972
   case VCODE_TYPE_CARRAY:
2973
      return vtype_is_signal(vt->elem);
49,950✔
2974
   default:
119,244✔
2975
      return false;
119,244✔
2976
   }
2977
}
2978

UNCOV
2979
int vtype_repr_bits(vtype_repr_t repr)
×
2980
{
UNCOV
2981
   switch (repr) {
×
2982
   case VCODE_REPR_U1: return 1;
2983
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2984
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2985
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2986
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2987
   default: return -1;
2988
   }
2989
}
2990

UNCOV
2991
bool vtype_repr_signed(vtype_repr_t repr)
×
2992
{
UNCOV
2993
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
×
UNCOV
2994
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
×
2995
}
2996

2997
static int64_t vtype_repr_low(vtype_repr_t repr)
13,710✔
2998
{
2999
   switch (repr) {
13,710✔
3000
   case VCODE_REPR_U1:
3001
   case VCODE_REPR_U8:
3002
   case VCODE_REPR_U16:
3003
   case VCODE_REPR_U32:
3004
   case VCODE_REPR_U64: return 0;
3005
   case VCODE_REPR_I8:  return INT8_MIN;
3006
   case VCODE_REPR_I16: return INT16_MIN;
3007
   case VCODE_REPR_I32: return INT32_MIN;
3008
   case VCODE_REPR_I64: return INT64_MIN;
3009
   default:             return 0;
3010
   }
3011
}
3012

3013
static uint64_t vtype_repr_high(vtype_repr_t repr)
13,710✔
3014
{
3015
   switch (repr) {
13,710✔
3016
   case VCODE_REPR_U1:  return 1;
3017
   case VCODE_REPR_U8:  return UINT8_MAX;
3018
   case VCODE_REPR_U16: return UINT16_MAX;
3019
   case VCODE_REPR_U32: return UINT32_MAX;
3020
   case VCODE_REPR_U64: return UINT64_MAX;
3021
   case VCODE_REPR_I8:  return INT8_MAX;
3022
   case VCODE_REPR_I16: return INT16_MAX;
3023
   case VCODE_REPR_I32: return INT32_MAX;
3024
   case VCODE_REPR_I64: return INT64_MAX;
3025
   default:             return 0;
3026
   }
3027
}
3028

3029
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
13,710✔
3030
{
3031
   int64_t clamp_low = vtype_repr_low(repr);
13,710✔
3032
   uint64_t clamp_high = vtype_repr_high(repr);
13,710✔
3033

3034
   if (*low >= clamp_low && *high <= clamp_high)
13,710✔
3035
      return true;
3036
   else {
3037
      *low = MAX(clamp_low, *low);
6,992✔
3038
      *high = MIN(clamp_high, *high);
6,992✔
3039
      return false;
6,992✔
3040
   }
3041
}
3042

3043
static vcode_stamp_t vstamp_new(const vstamp_t *s)
773,227✔
3044
{
3045
   assert(active_unit != NULL);
773,227✔
3046

3047
   for (int i = 0; i < active_unit->stamps.count; i++) {
7,596,429✔
3048
      vstamp_t *cmp = &(active_unit->stamps.items[i]);
7,259,515✔
3049
      if (cmp->kind == s->kind && memcmp(&cmp->u, &s->u, sizeof(s->u)) == 0)
7,259,515✔
3050
         return MAKE_HANDLE(active_unit->depth, i);
436,313✔
3051
   }
3052

3053
   vstamp_t *new = vstamp_array_alloc(&(active_unit->stamps));
336,914✔
3054
   *new = *s;
336,914✔
3055

3056
   return MAKE_HANDLE(active_unit->depth, active_unit->stamps.count - 1);
336,914✔
3057
}
3058

3059
vcode_stamp_t vstamp_int(int64_t low, int64_t high)
730,863✔
3060
{
3061
   const vstamp_t s = {
730,863✔
3062
      .kind = VCODE_STAMP_INT,
3063
      .u = { .intg = { .low = low, .high = high } },
3064
   };
3065
   return vstamp_new(&s);
730,863✔
3066
}
3067

3068
vcode_stamp_t vstamp_real(double low, double high)
42,364✔
3069
{
3070
   const vstamp_t s = {
42,364✔
3071
      .kind = VCODE_STAMP_REAL,
3072
      .u = { .real = { .low = low, .high = high } },
3073
   };
3074
   return vstamp_new(&s);
42,364✔
3075
}
3076

3077
vcode_stamp_t vstamp_char(void)
1,491✔
3078
{
3079
   return vstamp_int(0, 255);
1,491✔
3080
}
3081

3082
int vcode_count_params(void)
13,283✔
3083
{
3084
   assert(active_unit != NULL);
13,283✔
3085
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
13,283✔
3086
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3087
          || active_unit->kind == VCODE_UNIT_PROPERTY
3088
          || active_unit->kind == VCODE_UNIT_PROTECTED);
3089

3090
   return active_unit->params.count;
13,283✔
3091
}
3092

3093
vcode_type_t vcode_param_type(int param)
31,424✔
3094
{
3095
   assert(active_unit != NULL);
31,424✔
3096
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,424✔
3097
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3098
          || active_unit->kind == VCODE_UNIT_PROPERTY
3099
          || active_unit->kind == VCODE_UNIT_PROTECTED);
3100
   assert(param < active_unit->params.count);
31,424✔
3101

3102
   return active_unit->params.items[param].type;
31,424✔
3103
}
3104

3105
ident_t vcode_param_name(int param)
31,424✔
3106
{
3107
   assert(active_unit != NULL);
31,424✔
3108
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,424✔
3109
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3110
          || active_unit->kind == VCODE_UNIT_PROPERTY
3111
          || active_unit->kind == VCODE_UNIT_PROTECTED);
3112
   assert(param < active_unit->params.count);
31,424✔
3113

3114
   return active_unit->params.items[param].name;
31,424✔
3115
}
3116

3117
vcode_reg_t vcode_param_reg(int param)
31,424✔
3118
{
3119
   assert(active_unit != NULL);
31,424✔
3120
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,424✔
3121
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3122
          || active_unit->kind == VCODE_UNIT_PROPERTY
3123
          || active_unit->kind == VCODE_UNIT_PROTECTED);
3124
   assert(param < active_unit->params.count);
31,424✔
3125

3126
   return active_unit->params.items[param].reg;
31,424✔
3127
}
3128

3129
vcode_block_t emit_block(void)
137,719✔
3130
{
3131
   assert(active_unit != NULL);
137,719✔
3132

3133
   vcode_block_t bnum = active_unit->blocks.count;
137,719✔
3134

3135
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
137,719✔
3136
   memset(bptr, '\0', sizeof(block_t));
137,719✔
3137

3138
   if (active_block != VCODE_INVALID_BLOCK)
137,719✔
3139
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
86,903✔
3140
   else
3141
      bptr->last_loc = LOC_INVALID;
50,816✔
3142

3143
   return bnum;
137,719✔
3144
}
3145

3146
void vcode_select_unit(vcode_unit_t unit)
178,702✔
3147
{
3148
   active_unit  = unit;
178,702✔
3149
   active_block = VCODE_INVALID_BLOCK;
178,702✔
3150
}
178,702✔
3151

3152
void vcode_select_block(vcode_block_t block)
322,816✔
3153
{
3154
   assert(active_unit != NULL);
322,816✔
3155
   active_block = block;
322,816✔
3156
}
322,816✔
3157

3158
vcode_block_t vcode_active_block(void)
737✔
3159
{
3160
   assert(active_unit != NULL);
737✔
3161
   assert(active_block != -1);
737✔
3162
   return active_block;
737✔
3163
}
3164

3165
const loc_t *vcode_last_loc(void)
1,186,942✔
3166
{
3167
   return &(vcode_block_data()->last_loc);
1,186,942✔
3168
}
3169

3170
vcode_unit_t vcode_active_unit(void)
735✔
3171
{
3172
   assert(active_unit != NULL);
735✔
3173
   return active_unit;
735✔
3174
}
3175

3176
ident_t vcode_unit_name(vcode_unit_t vu)
156,761✔
3177
{
3178
   assert(vu != NULL);
156,761✔
3179
   return vu->name;
156,761✔
3180
}
3181

3182
bool vcode_unit_has_undefined(vcode_unit_t vu)
11,158✔
3183
{
3184
   assert(vu != NULL);
11,158✔
3185
   return !!(vu->flags & UNIT_UNDEFINED);
11,158✔
3186
}
3187

UNCOV
3188
int vcode_unit_depth(vcode_unit_t vu)
×
3189
{
UNCOV
3190
   assert(vu != NULL);
×
UNCOV
3191
   return vu->depth;
×
3192
}
3193

3194
void vcode_set_result(vcode_type_t type)
21,328✔
3195
{
3196
   assert(active_unit != NULL);
21,328✔
3197
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
21,328✔
3198
          || active_unit->kind == VCODE_UNIT_THUNK);
3199

3200
   active_unit->result = type;
21,328✔
3201
}
21,328✔
3202

3203
vcode_type_t vcode_unit_result(vcode_unit_t vu)
23,402✔
3204
{
3205
   assert(vu != NULL);
23,402✔
3206
   assert(vu->kind == VCODE_UNIT_FUNCTION || vu->kind == VCODE_UNIT_THUNK);
23,402✔
3207
   return vu->result;
23,402✔
3208
}
3209

3210
vunit_kind_t vcode_unit_kind(vcode_unit_t vu)
140,757✔
3211
{
3212
   assert(vu != NULL);
140,757✔
3213
   return vu->kind;
140,757✔
3214
}
3215

3216
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
78,806✔
3217
{
3218
   assert(vu != NULL);
78,806✔
3219
   return vu->context;
78,806✔
3220
}
3221

3222
object_t *vcode_unit_object(vcode_unit_t vu)
88,150✔
3223
{
3224
   assert(vu != NULL);
88,150✔
3225
   return vu->object;
88,150✔
3226
}
3227

3228
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
61,986✔
3229
{
3230
   int hops = 0;
61,986✔
3231
   for (; (unit = unit->context); hops++)
152,503✔
3232
      ;
3233
   return hops;
61,986✔
3234
}
3235

3236
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
27,648✔
3237
{
3238
   assert(context->kind != VCODE_UNIT_THUNK);
27,648✔
3239

3240
   child->next = NULL;
27,648✔
3241
   if (context->children == NULL)
27,648✔
3242
      context->children = child;
12,436✔
3243
   else {
3244
      vcode_unit_t it;
3245
      for (it = context->children; it->next != NULL; it = it->next)
70,326✔
3246
         ;
3247
      it->next = child;
15,212✔
3248
   }
3249
}
27,648✔
3250

3251
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
12,293✔
3252
{
3253
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
12,293✔
3254
   vu->kind     = VCODE_UNIT_FUNCTION;
12,293✔
3255
   vu->name     = name;
12,293✔
3256
   vu->context  = context;
12,293✔
3257
   vu->result   = VCODE_INVALID_TYPE;
12,293✔
3258
   vu->depth    = vcode_unit_calc_depth(vu);
12,293✔
3259
   vu->object   = obj;
12,293✔
3260

3261
   vcode_add_child(context, vu);
12,293✔
3262

3263
   vcode_select_unit(vu);
12,293✔
3264
   vcode_select_block(emit_block());
12,293✔
3265
   emit_debug_info(&(obj->loc));
12,293✔
3266

3267
   return vu;
12,293✔
3268
}
3269

3270
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
216✔
3271
{
3272
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
216✔
3273
   vu->kind     = VCODE_UNIT_PROCEDURE;
216✔
3274
   vu->name     = name;
216✔
3275
   vu->context  = context;
216✔
3276
   vu->result   = VCODE_INVALID_TYPE;
216✔
3277
   vu->depth    = vcode_unit_calc_depth(vu);
216✔
3278
   vu->object   = obj;
216✔
3279

3280
   vcode_add_child(context, vu);
216✔
3281

3282
   vcode_select_unit(vu);
216✔
3283
   vcode_select_block(emit_block());
216✔
3284
   emit_debug_info(&(obj->loc));
216✔
3285

3286
   return vu;
216✔
3287
}
3288

3289
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
7,635✔
3290
{
3291
   assert(context->kind == VCODE_UNIT_INSTANCE);
7,635✔
3292

3293
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
7,635✔
3294
   vu->kind     = VCODE_UNIT_PROCESS;
7,635✔
3295
   vu->name     = name;
7,635✔
3296
   vu->context  = context;
7,635✔
3297
   vu->depth    = vcode_unit_calc_depth(vu);
7,635✔
3298
   vu->result   = VCODE_INVALID_TYPE;
7,635✔
3299
   vu->object   = obj;
7,635✔
3300

3301
   vcode_add_child(context, vu);
7,635✔
3302

3303
   vcode_select_unit(vu);
7,635✔
3304
   vcode_select_block(emit_block());
7,635✔
3305
   emit_debug_info(&(obj->loc));
7,635✔
3306

3307
   return vu;
7,635✔
3308
}
3309

3310
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
10,027✔
3311
{
3312
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
10,027✔
3313

3314
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
10,027✔
3315
   vu->kind     = VCODE_UNIT_INSTANCE;
10,027✔
3316
   vu->name     = name;
10,027✔
3317
   vu->context  = context;
10,027✔
3318
   vu->depth    = vcode_unit_calc_depth(vu);
10,027✔
3319
   vu->result   = VCODE_INVALID_TYPE;
10,027✔
3320
   vu->object   = obj;
10,027✔
3321

3322
   if (context != NULL)
10,027✔
3323
      vcode_add_child(context, vu);
6,255✔
3324

3325
   vcode_select_unit(vu);
10,027✔
3326
   vcode_select_block(emit_block());
10,027✔
3327
   emit_debug_info(&(obj->loc));
10,027✔
3328

3329
   return vu;
10,027✔
3330
}
3331

3332
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
8,701✔
3333
{
3334
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
8,701✔
3335
   vu->kind     = VCODE_UNIT_PACKAGE;
8,701✔
3336
   vu->name     = name;
8,701✔
3337
   vu->context  = context;
8,701✔
3338
   vu->depth    = vcode_unit_calc_depth(vu);
8,701✔
3339
   vu->result   = VCODE_INVALID_TYPE;
8,701✔
3340
   vu->object   = obj;
8,701✔
3341

3342
   if (context != NULL)
8,701✔
3343
      vcode_add_child(context, vu);
189✔
3344

3345
   vcode_select_unit(vu);
8,701✔
3346
   vcode_select_block(emit_block());
8,701✔
3347
   emit_debug_info(&(obj->loc));
8,701✔
3348

3349
   return vu;
8,701✔
3350
}
3351

3352
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
534✔
3353
{
3354
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
534✔
3355
   vu->kind     = VCODE_UNIT_PROTECTED;
534✔
3356
   vu->name     = name;
534✔
3357
   vu->context  = context;
534✔
3358
   vu->depth    = vcode_unit_calc_depth(vu);
534✔
3359
   vu->result   = VCODE_INVALID_TYPE;
534✔
3360
   vu->object   = obj;
534✔
3361

3362
   if (context != NULL)
534✔
3363
      vcode_add_child(context, vu);
534✔
3364

3365
   vcode_select_unit(vu);
534✔
3366
   vcode_select_block(emit_block());
534✔
3367
   emit_debug_info(&(obj->loc));
534✔
3368

3369
   return vu;
534✔
3370
}
3371

3372
vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context)
240✔
3373
{
3374
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
240✔
3375
   vu->kind     = VCODE_UNIT_PROPERTY;
240✔
3376
   vu->name     = name;
240✔
3377
   vu->context  = context;
240✔
3378
   vu->depth    = vcode_unit_calc_depth(vu);
240✔
3379
   vu->result   = VCODE_INVALID_TYPE;
240✔
3380
   vu->object   = obj;
240✔
3381

3382
   if (context != NULL)
240✔
3383
      vcode_add_child(context, vu);
240✔
3384

3385
   vcode_select_unit(vu);
240✔
3386
   vcode_select_block(emit_block());
240✔
3387
   emit_debug_info(&(obj->loc));
240✔
3388

3389
   return vu;
240✔
3390
}
3391

3392
vcode_unit_t emit_thunk(ident_t name, object_t *obj, vcode_unit_t context)
11,170✔
3393
{
3394
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
11,170✔
3395
   vu->kind     = VCODE_UNIT_THUNK;
11,170✔
3396
   vu->name     = name;
11,170✔
3397
   vu->context  = context;
11,170✔
3398
   vu->depth    = vcode_unit_calc_depth(vu);
11,170✔
3399
   vu->result   = VCODE_INVALID_TYPE;
11,170✔
3400
   vu->depth    = vcode_unit_calc_depth(vu);
11,170✔
3401
   vu->object   = obj;
11,170✔
3402

3403
   if (context != NULL)
11,170✔
3404
      vcode_add_child(context, vu);
286✔
3405

3406
   vcode_select_unit(vu);
11,170✔
3407
   vcode_select_block(emit_block());
11,170✔
3408

3409
   return vu;
11,170✔
3410
}
3411

3412
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
14,658✔
3413
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3414
                 vcode_reg_t hint_right)
3415
{
3416
   int64_t value_const;
14,658✔
3417
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
14,658✔
3418
      emit_comment("Always true assertion on r%d", value);
30✔
3419
      return;
30✔
3420
   }
3421

3422
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
14,628✔
3423
   vcode_add_arg(op, value);
14,628✔
3424
   vcode_add_arg(op, severity);
14,628✔
3425
   vcode_add_arg(op, message);
14,628✔
3426
   vcode_add_arg(op, length);
14,628✔
3427
   vcode_add_arg(op, locus);
14,628✔
3428

3429
   if (hint_left != VCODE_INVALID_REG) {
14,628✔
3430
      vcode_add_arg(op, hint_left);
6,088✔
3431
      vcode_add_arg(op, hint_right);
6,088✔
3432

3433
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
6,088✔
3434
                   "left hint must be scalar");
3435
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
6,088✔
3436
                   "right hint must be scalar");
3437
   }
3438

3439
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
14,628✔
3440
                "value parameter to assert is not bool");
3441
   VCODE_ASSERT(message == VCODE_INVALID_REG
14,628✔
3442
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3443
                "message parameter to assert is not a pointer");
3444
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
14,628✔
3445
                "value parameter to assert is not bool");
3446
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
14,628✔
3447
                "locus argument to report must be a debug locus");
3448
}
3449

3450
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,077✔
3451
                 vcode_reg_t locus)
3452
{
3453
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,077✔
3454
   vcode_add_arg(op, severity);
2,077✔
3455
   vcode_add_arg(op, message);
2,077✔
3456
   vcode_add_arg(op, length);
2,077✔
3457
   vcode_add_arg(op, locus);
2,077✔
3458

3459
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,077✔
3460
                "message parameter to report is not a pointer");
3461
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,077✔
3462
                "message parameter to report is not a character pointer");
3463
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,077✔
3464
                "locus argument to report must be a debug locus");
3465
}
2,077✔
3466

3467
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
34,600✔
3468
{
3469
   if (lhs == rhs) {
34,600✔
3470
      if (cmp == VCODE_CMP_EQ)
398✔
3471
         return emit_const(vtype_bool(), 1);
242✔
3472
      else if (cmp == VCODE_CMP_NEQ)
156✔
3473
         return emit_const(vtype_bool(), 0);
×
3474
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
156✔
3475
         return emit_const(vtype_bool(), 1);
×
3476
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
156✔
3477
         return emit_const(vtype_bool(), 0);
156✔
3478
   }
3479

3480
   int64_t lconst, rconst;
34,202✔
3481
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
34,202✔
3482
      switch (cmp) {
334✔
3483
      case VCODE_CMP_EQ:
312✔
3484
         return emit_const(vtype_bool(), lconst == rconst);
312✔
3485
      case VCODE_CMP_NEQ:
3✔
3486
         return emit_const(vtype_bool(), lconst != rconst);
3✔
3487
      case VCODE_CMP_LT:
9✔
3488
         return emit_const(vtype_bool(), lconst < rconst);
9✔
3489
      case VCODE_CMP_GT:
10✔
3490
         return emit_const(vtype_bool(), lconst > rconst);
10✔
UNCOV
3491
      case VCODE_CMP_LEQ:
×
UNCOV
3492
         return emit_const(vtype_bool(), lconst <= rconst);
×
UNCOV
3493
      case VCODE_CMP_GEQ:
×
UNCOV
3494
         return emit_const(vtype_bool(), lconst >= rconst);
×
UNCOV
3495
      default:
×
3496
         fatal_trace("cannot fold comparison %d", cmp);
3497
      }
3498
   }
3499

3500
   // Reuse any previous operation in this block with the same arguments
3501
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
662,550✔
3502
      if (other->args.count == 2 && other->args.items[0] == lhs
24,433✔
3503
          && other->args.items[1] == rhs && other->cmp == cmp)
2,276✔
3504
         return other->result;
193✔
3505
   }
3506

3507
   op_t *op = vcode_add_op(VCODE_OP_CMP);
33,675✔
3508
   vcode_add_arg(op, lhs);
33,675✔
3509
   vcode_add_arg(op, rhs);
33,675✔
3510
   op->cmp    = cmp;
33,675✔
3511
   op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP);
33,675✔
3512

3513
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
33,675✔
3514
                "arguments to cmp are not the same type");
3515

3516
   return op->result;
33,675✔
3517
}
3518

3519
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_stamp_t stamp,
34,291✔
3520
                       const vcode_reg_t *args, int nargs)
3521
{
3522
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
34,291✔
3523
   o->func = func;
34,291✔
3524
   o->type = type;
34,291✔
3525
   for (int i = 0; i < nargs; i++)
120,566✔
3526
      vcode_add_arg(o, args[i]);
86,275✔
3527

3528
   for (int i = 0; i < nargs; i++)
120,566✔
3529
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
86,275✔
3530
                   "invalid argument to function");
3531

3532
   if (type == VCODE_INVALID_TYPE)
34,291✔
3533
      return (o->result = VCODE_INVALID_REG);
5,535✔
3534
   else
3535
      return (o->result = vcode_add_reg(type, stamp));
28,756✔
3536
}
3537

3538
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
843✔
3539
                vcode_block_t resume_bb)
3540
{
3541
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
843✔
3542
   o->func = func;
843✔
3543
   for (int i = 0; i < nargs; i++)
2,845✔
3544
      vcode_add_arg(o, args[i]);
2,002✔
3545

3546
   vcode_block_array_add(&(o->targets), resume_bb);
843✔
3547

3548
   for (int i = 0; i < nargs; i++)
2,845✔
3549
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,002✔
3550
                   "invalid argument to procedure");
3551

3552
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
843✔
3553
                "first argument to VHDL procedure must be context pointer");
3554
}
843✔
3555

3556
vcode_reg_t emit_alloc(vcode_type_t type, vcode_stamp_t stamp,
7,284✔
3557
                       vcode_reg_t count)
3558
{
3559
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
7,284✔
3560
   op->type = type;
7,284✔
3561
   vcode_add_arg(op, count);
7,284✔
3562

3563
   const vtype_kind_t tkind = vtype_kind(type);
7,284✔
3564
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
7,284✔
3565
                "alloca element type cannot be array");
3566
   VCODE_ASSERT(count != VCODE_INVALID_REG,
7,284✔
3567
                "alloca must have valid count argument");
3568

3569
   return (op->result = vcode_add_reg(vtype_pointer(type), stamp));
7,284✔
3570
}
3571

3572
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
1,445,740✔
3573
{
3574
   // Reuse any previous constant in this block with the same type and value
3575
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
33,021,407✔
3576
      if (other->value == value && vtype_eq(type, other->type))
11,675,160✔
3577
         return other->result;
997,293✔
3578
   }
3579

3580
   op_t *op = vcode_add_op(VCODE_OP_CONST);
448,447✔
3581
   op->value  = value;
448,447✔
3582
   op->type   = type;
448,447✔
3583
   op->result = vcode_add_reg(type, vstamp_int(value, value));
448,447✔
3584

3585
   vtype_kind_t type_kind = vtype_kind(type);
448,447✔
3586
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
448,447✔
3587
                "constant must have integer or offset type");
3588

3589
   return op->result;
3590
}
3591

3592
vcode_reg_t emit_const_real(vcode_type_t type, double value)
66,690✔
3593
{
3594
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
1,955,793✔
3595
      if (other->real == value && other->type == type)
907,873✔
3596
         return other->result;
25,295✔
3597
   }
3598

3599
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
41,395✔
3600
   op->real   = value;
41,395✔
3601
   op->type   = type;
41,395✔
3602
   op->result = vcode_add_reg(op->type, vstamp_real(value, value));
41,395✔
3603

3604
   return op->result;
41,395✔
3605
}
3606

3607
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
37,421✔
3608
{
3609
   vtype_kind_t kind = vtype_kind(type);
37,421✔
3610

3611
   // Reuse any previous operation in this block with the same arguments
3612
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,921,591✔
3613
      if (other->args.count != num)
151,430✔
3614
         continue;
90,291✔
3615
      else if (!vtype_eq(vcode_reg_type(other->result), type))
61,139✔
3616
         continue;
2,333✔
3617

3618
      bool match = true;
3619
      for (int i = 0; match && i < num; i++) {
422,388✔
3620
         if (other->args.items[i] != values[i])
363,582✔
3621
            match = false;
51,732✔
3622
      }
3623

3624
      if (match) return other->result;
58,806✔
3625
   }
3626

3627
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
30,347✔
3628
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
30,347✔
3629

3630
   for (int i = 0; i < num; i++)
1,680,425✔
3631
      vcode_add_arg(op, values[i]);
1,650,078✔
3632

3633
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
30,347✔
3634
                "constant array must have constrained array type");
3635
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
30,347✔
3636
                vtype_size(type), num);
3637

3638
#ifdef DEBUG
3639
   vcode_type_t elem = vtype_elem(type);
30,347✔
3640
   for (int i = 0; i < num; i++) {
1,680,425✔
3641
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,650,078✔
3642
                   "wrong element type for item %d", i);
3643
      vcode_assert_const(values[i], "array");
1,650,078✔
3644
   }
3645
#endif
3646

3647
   return op->result;
30,347✔
3648
}
3649

3650
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
500✔
3651
{
3652
   // Reuse any previous operation in this block with the same arguments
3653
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
8,311✔
3654
      if (other->args.items[0] == value && other->value == rep)
607✔
3655
         return other->result;
198✔
3656
   }
3657

3658
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
302✔
3659
   op->value = rep;
302✔
3660
   vcode_add_arg(op, value);
302✔
3661

3662
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
302✔
3663
                "constant array must have constrained array type");
3664
   VCODE_ASSERT(rep >= 0, "repeat count must be non-negative");
302✔
3665

3666
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
302✔
3667

3668
   return (op->result = vcode_add_reg(type, vcode_reg_data(value)->stamp));
302✔
3669
}
3670

3671
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
2,519✔
3672
{
3673
   // Reuse any previous constant in this block with the same type and value
3674
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
38,739✔
3675
      if (other->args.count == num && vtype_eq(type, other->type)) {
1,534✔
3676
         bool same_regs = true;
3677
         for (int i = 0; same_regs && i < num; i++)
2,504✔
3678
            same_regs = other->args.items[i] == values[i];
1,454✔
3679

3680
         if (same_regs)
1,050✔
3681
            return other->result;
187✔
3682
      }
3683
   }
3684

3685
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
2,332✔
3686
   op->type   = type;
2,332✔
3687
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
2,332✔
3688

3689
   for (int i = 0; i < num; i++)
8,332✔
3690
      vcode_add_arg(op, values[i]);
6,000✔
3691

3692
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
2,332✔
3693
                "constant record must have record type");
3694

3695
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
2,332✔
3696
                vtype_fields(type), num);
3697

3698
#ifdef DEBUG
3699
   for (int i = 0; i < num; i++) {
8,332✔
3700
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
6,000✔
3701
                   "wrong type for field %d", i);
3702
      vcode_assert_const(values[i], "record");
6,000✔
3703
   }
3704
#endif
3705

3706
   return op->result;
2,332✔
3707
}
3708

3709
vcode_reg_t emit_address_of(vcode_reg_t value)
38,988✔
3710
{
3711
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
1,995,814✔
3712
      if (other->args.items[0] == value)
152,430✔
3713
         return other->result;
7,069✔
3714
   }
3715

3716
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
31,919✔
3717
   vcode_add_arg(op, value);
31,919✔
3718

3719
   vcode_type_t vtype = vcode_reg_type(value);
31,919✔
3720

3721
   VCODE_ASSERT(vtype_is_composite(vtype),
31,919✔
3722
                "address of argument must be record or array");
3723

3724
   if (vtype_kind(vtype) == VCODE_TYPE_CARRAY) {
31,919✔
3725
      vcode_type_t elem = vtype_elem(vtype);
30,127✔
3726
      vcode_stamp_t stamp = vcode_reg_stamp(value);
30,127✔
3727
      return (op->result = vcode_add_reg(vtype_pointer(elem), stamp));
30,127✔
3728
   }
3729
   else {
3730
      vcode_stamp_t stamp = VCODE_INVALID_STAMP;
1,792✔
3731
      return (op->result = vcode_add_reg(vtype_pointer(vtype), stamp));
1,792✔
3732
   }
3733
}
3734

3735
void emit_wait(vcode_block_t target)
12,821✔
3736
{
3737
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
12,821✔
3738
   vcode_add_target(op, target);
12,821✔
3739
}
12,821✔
3740

3741
void emit_jump(vcode_block_t target)
36,086✔
3742
{
3743
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
36,086✔
3744
   vcode_add_target(op, target);
36,086✔
3745

3746
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
36,086✔
3747
}
36,086✔
3748

3749
vcode_var_t emit_var(vcode_type_t type, vcode_stamp_t stamp, ident_t name,
70,665✔
3750
                     vcode_var_flags_t flags)
3751
{
3752
   assert(active_unit != NULL);
70,665✔
3753

3754
   vcode_var_t var = active_unit->vars.count;
70,665✔
3755
   var_t *v = var_array_alloc(&(active_unit->vars));
70,665✔
3756
   memset(v, '\0', sizeof(var_t));
70,665✔
3757
   v->type  = type;
70,665✔
3758
   v->stamp = stamp;
70,665✔
3759
   v->name  = name;
70,665✔
3760
   v->flags = flags;
70,665✔
3761

3762
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
70,665✔
3763

3764
   return var;
70,665✔
3765
}
3766

3767
vcode_reg_t emit_param(vcode_type_t type, vcode_stamp_t stamp, ident_t name)
31,710✔
3768
{
3769
   assert(active_unit != NULL);
31,710✔
3770

3771
   param_t *p = param_array_alloc(&(active_unit->params));
31,710✔
3772
   memset(p, '\0', sizeof(param_t));
31,710✔
3773
   p->type  = type;
31,710✔
3774
   p->stamp = stamp;
31,710✔
3775
   p->name  = name;
31,710✔
3776
   p->reg   = vcode_add_reg(type, stamp);
31,710✔
3777

3778
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
31,710✔
3779

3780
   return p->reg;
31,710✔
3781
}
3782

3783
vcode_reg_t emit_load(vcode_var_t var)
60,230✔
3784
{
3785
   // Try scanning backwards through the block for another load or store to
3786
   // this variable
3787
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
60,230✔
3788
   vcode_reg_t fold = VCODE_INVALID_REG;
60,230✔
3789
   VCODE_FOR_EACH_OP(other) {
863,785✔
3790
      switch (state) {
819,838✔
3791
      case EAGER:
332,608✔
3792
         if (other->kind == VCODE_OP_LOAD && other->address == var)
332,608✔
3793
            return other->result;
3,806✔
3794
         else if (other->kind == VCODE_OP_STORE && other->address == var)
328,802✔
3795
            return other->args.items[0];
12,477✔
3796
         else if (other->kind == VCODE_OP_FCALL
316,325✔
3797
                  || other->kind == VCODE_OP_PCALL
316,325✔
3798
                  || other->kind == VCODE_OP_FILE_READ
3799
                  || other->kind == VCODE_OP_FILE_OPEN
3800
                  || other->kind == VCODE_OP_STORE_INDIRECT
3801
                  || other->kind == VCODE_OP_DEALLOCATE)
3802
            state = CONSERVATIVE;   // May write to variable
9,734✔
3803
         break;
3804

3805
      case CONSERVATIVE:
456,152✔
3806
         if (other->kind == VCODE_OP_LOAD && other->address == var
456,152✔
3807
             && fold == VCODE_INVALID_REG)
4,464✔
3808
            fold = other->result;
3,585✔
3809
         else if (other->kind == VCODE_OP_STORE && other->address == var
452,567✔
3810
                  && fold == VCODE_INVALID_REG)
2,408✔
3811
            fold = other->args.items[0];
2,266✔
3812
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
450,301✔
3813
            state = UNSAFE;
3814
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
448,897✔
3815
            state = UNSAFE;   // Nested call captures variables
112✔
3816
         break;
3817

3818
      case UNSAFE:
3819
         break;
3820
      }
3821
   }
3822

3823
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
43,947✔
3824
      return fold;
3825

3826
   var_t *v = vcode_var_data(var);
38,478✔
3827

3828
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
38,478✔
3829
   op->address = var;
38,478✔
3830
   op->result  = vcode_add_reg(v->type, v->stamp);
38,478✔
3831

3832
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
38,478✔
3833

3834
   return op->result;
3835
}
3836

3837
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
93,242✔
3838
{
3839
   VCODE_FOR_EACH_OP(other) {
1,111,205✔
3840
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,048,169✔
3841
          && other->args.items[0] == reg) {
151,317✔
3842
         return other->result;
9,959✔
3843
      }
3844
      else if (other->kind == VCODE_OP_FCALL
1,038,210✔
3845
               || other->kind == VCODE_OP_PCALL
1,038,210✔
3846
               || other->kind == VCODE_OP_STORE
3847
               || other->kind == VCODE_OP_STORE_INDIRECT
3848
               || other->kind == VCODE_OP_MEMSET
3849
               || other->kind == VCODE_OP_COPY
3850
               || other->kind == VCODE_OP_FILE_READ)
3851
         break;   // May write to this pointer
3852
   }
3853

3854
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
83,283✔
3855
   vcode_add_arg(op, reg);
83,283✔
3856

3857
   vcode_type_t rtype = vcode_reg_type(reg);
83,283✔
3858

3859
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
83,283✔
3860
                "load indirect with non-pointer argument");
3861

3862
   vcode_type_t deref = vtype_pointed(rtype);
83,283✔
3863
   op->result = vcode_add_reg(deref, vcode_reg_stamp(reg));
83,283✔
3864

3865
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
83,283✔
3866

3867
   return op->result;
3868
}
3869

3870
void emit_store(vcode_reg_t reg, vcode_var_t var)
75,443✔
3871
{
3872
   // Any previous store to this variable in this block is dead
3873
   VCODE_FOR_EACH_OP(other) {
1,605,106✔
3874
      if (other->kind == VCODE_OP_STORE && other->address == var) {
1,544,141✔
3875
         other->kind = VCODE_OP_COMMENT;
291✔
3876
         other->comment =
582✔
3877
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
291✔
3878
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
291✔
3879
      }
3880
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
1,543,850✔
3881
         break;   // Needs to get variable for display
3882
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
1,537,575✔
3883
               && other->address == var)
37,579✔
3884
         break;   // Previous value may be used
3885
   }
3886

3887
   var_t *v = vcode_var_data(var);
75,443✔
3888
   reg_t *r = vcode_reg_data(reg);
75,443✔
3889

3890
   op_t *op = vcode_add_op(VCODE_OP_STORE);
75,443✔
3891
   vcode_add_arg(op, reg);
75,443✔
3892
   op->address = var;
75,443✔
3893

3894
   VCODE_ASSERT(vtype_eq(v->type, r->type),
75,443✔
3895
                "variable and stored value do not have same type");
3896
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
75,443✔
3897
}
75,443✔
3898

3899
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
14,927✔
3900
{
3901
   reg_t *p = vcode_reg_data(ptr);
14,927✔
3902
   reg_t *r = vcode_reg_data(reg);
14,927✔
3903

3904
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
14,927✔
3905
   vcode_add_arg(op, reg);
14,927✔
3906
   vcode_add_arg(op, ptr);
14,927✔
3907

3908
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
14,927✔
3909
                "store indirect target is not a pointer");
3910
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
14,927✔
3911
                "pointer and stored value do not have same type");
3912
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
14,927✔
3913
}
14,927✔
3914

3915
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
67,033✔
3916
                              vcode_reg_t locus)
3917
{
3918
   // Reuse any previous operation in this block with the same arguments
3919
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,564,630✔
3920
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
77,122✔
3921
         return other->result;
5,878✔
3922
   }
3923

3924
   op_t *op = vcode_add_op(kind);
61,155✔
3925
   vcode_add_arg(op, lhs);
61,155✔
3926
   vcode_add_arg(op, rhs);
61,155✔
3927
   if (locus != VCODE_INVALID_REG)
61,155✔
3928
      vcode_add_arg(op, locus);
7,775✔
3929

3930
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
61,155✔
3931

3932
   vcode_type_t lhs_type = vcode_reg_type(lhs);
61,155✔
3933
   vcode_type_t rhs_type = vcode_reg_type(rhs);
61,155✔
3934

3935
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
61,155✔
3936
                "arguments to %s are not the same type", vcode_op_string(kind));
3937

3938
   return op->result;
61,155✔
3939
}
3940

3941
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
48,066✔
3942
                               vcode_reg_t locus)
3943
{
3944
   int64_t lconst, rconst;
48,066✔
3945
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
48,066✔
3946
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
48,066✔
3947
   if (l_is_const && r_is_const)
48,066✔
3948
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
22,207✔
3949
   else if (r_is_const && rconst == 1)
25,859✔
3950
      return lhs;
3951
   else if (l_is_const && lconst == 1)
4,851✔
3952
      return rhs;
3953
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
4,349✔
3954
      return emit_const(vcode_reg_type(lhs), 0);
54✔
3955

3956
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
4,295✔
3957

3958
   double rl_low, rl_high, rr_low, rr_high;
4,295✔
3959
   int64_t l_low, l_high, r_low, r_high;
4,295✔
3960

3961
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
4,295✔
3962
       && vcode_reg_bounds(rhs, &r_low, &r_high)) {
3,739✔
3963
      const int64_t ll = smul64(l_low, r_low);
3,739✔
3964
      const int64_t lh = smul64(l_low, r_high);
3,739✔
3965
      const int64_t hl = smul64(l_high, r_low);
3,739✔
3966
      const int64_t hh = smul64(l_high, r_high);
3,739✔
3967

3968
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
3,739✔
3969
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
3,739✔
3970

3971
      if (min > INT64_MIN && max < INT64_MAX) {
3,739✔
3972
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
2,095✔
3973
         if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
2,095✔
3974
            op = VCODE_OP_MUL;   // Cannot overflow
613✔
3975
            locus = VCODE_INVALID_REG;
613✔
3976
         }
3977
      }
3978

3979
      vstamp = vstamp_int(min, max);
3,739✔
3980
   }
3981
   else if (vcode_reg_bounds_real(lhs, &rl_low, &rl_high)
556✔
3982
            && vcode_reg_bounds_real(rhs, &rr_low, &rr_high)) {
556✔
3983
      const double ll = rl_low * rr_low;
556✔
3984
      const double lh = rl_low * rr_high;
556✔
3985
      const double hl = rl_high * rr_low;
556✔
3986
      const double hh = rl_high * rr_high;
556✔
3987

3988
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,301✔
3989
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,387✔
3990

3991
      vstamp = vstamp_real(min, max);
556✔
3992
   }
3993

3994
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
4,295✔
3995

3996
   if (vstamp != VCODE_INVALID_TYPE)
4,295✔
3997
      vcode_reg_data(reg)->stamp = vstamp;
4,295✔
3998

3999
   return reg;
4000
}
4001

4002
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
45,253✔
4003
{
4004
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
45,253✔
4005
}
4006

4007
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
2,813✔
4008
{
4009
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
2,813✔
4010

4011
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
2,813✔
4012
                "trapping add may only be used with integer types");
4013

4014
   return result;
2,813✔
4015
}
4016

4017
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
1,750✔
4018
{
4019
   int64_t lconst, rconst;
1,750✔
4020
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
1,750✔
4021
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
1,750✔
4022
   if (l_is_const && r_is_const && rconst != 0)
1,750✔
4023
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
30✔
4024
   else if (r_is_const && rconst == 1)
1,720✔
4025
      return lhs;
4026

4027
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
1,717✔
4028

4029
   int64_t l_low, l_high;
1,717✔
4030
   if (vcode_reg_bounds(lhs, &l_low, &l_high)) {
1,717✔
4031
      if (r_is_const && rconst != 0) {
1,400✔
4032
         reg_t *rr = vcode_reg_data(reg);
1,324✔
4033
         rr->stamp = vstamp_int(l_low / rconst, l_high / rconst);
1,324✔
4034
      }
4035
   }
4036
   else {
4037
      reg_t *rr = vcode_reg_data(reg);
317✔
4038
      rr->stamp = vstamp_real(-INFINITY, INFINITY);
317✔
4039
   }
4040

4041
   return reg;
4042
}
4043

4044
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
141✔
4045
{
4046
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
141✔
4047
}
4048

4049
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
411✔
4050
{
4051
   int64_t rconst;
411✔
4052
   if (vcode_reg_const(rhs, &rconst)) {
411✔
4053
      if (rconst == 0)
77✔
4054
         return emit_const(vcode_reg_type(lhs), 1);
31✔
4055
      else if (rconst == 1)
46✔
4056
         return lhs;
4057
   }
4058

4059
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
379✔
4060

4061
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
379✔
4062
                "trapping exp may only be used with integer types");
4063

4064
   return result;
4065
}
4066

4067
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
199✔
4068
{
4069
   int64_t lconst, rconst;
199✔
4070
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
199✔
4071
       && lconst > 0 && rconst > 0)
15✔
4072
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
3✔
4073

4074
   int64_t l_low, l_high, r_low, r_high;
196✔
4075
   if (vcode_reg_bounds(lhs, &l_low, &l_high) && l_low >= 0
196✔
4076
       && vcode_reg_bounds(rhs, &r_low, &r_high) && r_low >= 0) {
91✔
4077
      // If both arguments are non-negative then rem is equivalent and
4078
      // cheaper to compute
4079
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
87✔
4080

4081
      reg_t *rr = vcode_reg_data(reg);
87✔
4082
      rr->stamp = vstamp_int(0, MAX(0, r_high - 1));
87✔
4083

4084
      return reg;
87✔
4085
   }
4086
   else
4087
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
109✔
4088
}
4089

4090
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
873✔
4091
{
4092
   int64_t lconst, rconst;
873✔
4093
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
873✔
4094
       && lconst > 0 && rconst > 0)
2✔
UNCOV
4095
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
4096

4097
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
873✔
4098

4099
   int64_t l_low, l_high, r_low, r_high;
873✔
4100
   if (vcode_reg_bounds(lhs, &l_low, &l_high) && l_low >= 0
873✔
4101
       && vcode_reg_bounds(rhs, &r_low, &r_high) && r_low >= 0) {
496✔
4102
      reg_t *rr = vcode_reg_data(reg);
492✔
4103
      rr->stamp = vstamp_int(0, r_high - 1);
492✔
4104
   }
4105

4106
   return reg;
4107
}
4108

4109
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
47,997✔
4110
                               vcode_reg_t locus)
4111
{
4112
   int64_t lconst, rconst;
47,997✔
4113
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
47,997✔
4114
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
47,997✔
4115
   if (l_is_const && r_is_const)
47,997✔
4116
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
11,958✔
4117
   else if (r_is_const && rconst == 0)
36,039✔
4118
      return lhs;
4119
   else if (l_is_const && lconst == 0)
35,911✔
4120
      return rhs;
4121

4122
   int64_t l_low, l_high, r_low, r_high;
19,842✔
4123
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
19,842✔
4124
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
19,842✔
4125
       && vcode_reg_bounds(rhs, &r_low, &r_high))  {
19,518✔
4126

4127
      int64_t rbl = sadd64(l_low, r_low);
19,518✔
4128
      int64_t rbh = sadd64(l_high, r_high);
19,518✔
4129

4130
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
19,518✔
4131
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
10,516✔
4132
         if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
10,516✔
4133
            op = VCODE_OP_ADD;   // Cannot overflow
1,172✔
4134
            locus = VCODE_INVALID_REG;
1,172✔
4135
         }
4136
      }
4137

4138
      vstamp = vstamp_int(rbl, rbh);
19,518✔
4139
   }
4140

4141
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
19,842✔
4142

4143
   if (vstamp != VCODE_INVALID_STAMP)
19,842✔
4144
      vcode_reg_data(reg)->stamp = vstamp;
19,518✔
4145

4146
   return reg;
4147
}
4148

4149
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
41,750✔
4150
{
4151
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
41,750✔
4152
}
4153

4154
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
6,247✔
4155
{
4156
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
6,247✔
4157

4158
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
6,247✔
4159
                "trapping add may only be used with integer types");
4160

4161
   return result;
6,247✔
4162
}
4163

4164
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
46,165✔
4165
                               vcode_reg_t locus)
4166
{
4167
   int64_t lconst, rconst;
46,165✔
4168
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
46,165✔
4169
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
46,165✔
4170
   if (l_is_const && r_is_const)
46,165✔
4171
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
8,306✔
4172
   else if (r_is_const && rconst == 0)
37,859✔
4173
      return lhs;
4174
   else if (l_is_const && lconst == 0)
33,490✔
4175
      return emit_neg(rhs);
840✔
4176

4177
   int64_t l_low, l_high, r_low, r_high;
32,650✔
4178
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
32,650✔
4179
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
32,650✔
4180
       && vcode_reg_bounds(rhs, &r_low, &r_high))  {
32,355✔
4181

4182
      int64_t rbl = ssub64(l_low, r_high);
32,355✔
4183
      int64_t rbh = ssub64(l_high, r_low);
32,355✔
4184

4185
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
32,355✔
4186
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
29,982✔
4187
         if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
29,982✔
4188
            op = VCODE_OP_SUB;   // Cannot overflow
4,933✔
4189
            locus = VCODE_INVALID_REG;
4,933✔
4190
         }
4191
      }
4192

4193
      vstamp = vstamp_int(rbl, rbh);
32,355✔
4194
   }
4195

4196
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
32,650✔
4197

4198
   if (vstamp != VCODE_INVALID_TYPE)
32,650✔
4199
      vcode_reg_data(reg)->stamp = vstamp;
32,355✔
4200

4201
   return reg;
4202
}
4203

4204
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
39,055✔
4205
{
4206
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
39,055✔
4207
}
4208

4209
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
7,110✔
4210
{
4211
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
7,110✔
4212

4213
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
7,110✔
4214
                "trapping sub may only be used with integer types");
4215

4216
   return result;
7,110✔
4217
}
4218

4219
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
70,205✔
4220
{
4221
   switch (vtype_kind(var->type)) {
70,205✔
4222
   case VCODE_TYPE_CARRAY:
21,600✔
4223
      op->type = vtype_pointer(vtype_elem(var->type));
21,600✔
4224
      op->result = vcode_add_reg(op->type, var->stamp);
21,600✔
4225
      break;
21,600✔
4226

4227
   case VCODE_TYPE_RECORD:
5,761✔
4228
      op->type = vtype_pointer(var->type);
5,761✔
4229
      op->result = vcode_add_reg(op->type, VCODE_INVALID_STAMP);
5,761✔
4230
      break;
5,761✔
4231

4232
   case VCODE_TYPE_INT:
42,844✔
4233
   case VCODE_TYPE_FILE:
4234
   case VCODE_TYPE_ACCESS:
4235
   case VCODE_TYPE_REAL:
4236
   case VCODE_TYPE_UARRAY:
4237
   case VCODE_TYPE_POINTER:
4238
   case VCODE_TYPE_SIGNAL:
4239
   case VCODE_TYPE_CONTEXT:
4240
   case VCODE_TYPE_OFFSET:
4241
   case VCODE_TYPE_TRIGGER:
4242
   case VCODE_TYPE_RESOLUTION:
4243
      op->type = vtype_pointer(var->type);
42,844✔
4244
      op->result = vcode_add_reg(op->type, var->stamp);
42,844✔
4245
      break;
42,844✔
4246

4247
   default:
UNCOV
4248
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4249
                   istr(var->name));
4250
   }
4251
}
70,205✔
4252

4253
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
34,083✔
4254
{
4255
   // Try to find a previous index of this var by this offset
4256
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
1,391,523✔
4257
      if (other->address == var
83,607✔
4258
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
7,217✔
UNCOV
4259
              || (offset != VCODE_INVALID_REG
×
UNCOV
4260
                  && other->args.items[0] == offset)))
×
4261
         return other->result;
7,217✔
4262
   }
4263

4264
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
26,866✔
4265
   op->address = var;
26,866✔
4266

4267
   if (offset != VCODE_INVALID_REG)
26,866✔
UNCOV
4268
      vcode_add_arg(op, offset);
×
4269

4270
   vcode_calculate_var_index_type(op, vcode_var_data(var));
26,866✔
4271

4272
   if (offset != VCODE_INVALID_REG)
26,866✔
UNCOV
4273
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4274
                   "index offset r%d does not have offset type", offset);
4275

4276
   return op->result;
26,866✔
4277
}
4278

4279
vcode_reg_t emit_cast(vcode_type_t type, vcode_stamp_t stamp, vcode_reg_t reg)
242,938✔
4280
{
4281
   if (vtype_eq(vcode_reg_type(reg), type))
242,938✔
4282
      return reg;
242,938✔
4283

4284
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
81,795✔
4285
   vtype_kind_t to   = vtype_kind(type);
81,795✔
4286

4287
   const bool integral =
163,590✔
4288
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
81,795✔
4289
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
81,795✔
4290

4291
   int64_t value;
81,795✔
4292
   if (integral && vcode_reg_const(reg, &value))
81,795✔
4293
      return emit_const(type, value);
12,743✔
4294

4295
   // Try to find a previous cast of this register to this type
4296
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,367,500✔
4297
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
139,627✔
4298
         return other->result;
15,345✔
4299
   }
4300

4301
   op_t *op = vcode_add_op(VCODE_OP_CAST);
53,707✔
4302
   vcode_add_arg(op, reg);
53,707✔
4303
   op->type  = type;
53,707✔
4304

4305
   static const vcode_type_t allowed[][2] = {
53,707✔
4306
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4307
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4308
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4309
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4310
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4311
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4312
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4313
   };
4314

4315
   if (integral) {
53,707✔
4316
      vtype_t *vt = vcode_type_data(type);
52,865✔
4317
      int64_t low = vt->low, high = vt->high;
52,865✔
4318

4319
      vstamp_t *rt = vcode_stamp_data(vcode_reg_data(reg)->stamp);
52,865✔
4320
      if (rt != NULL) {
52,865✔
4321
         VCODE_ASSERT(rt->kind == VCODE_STAMP_INT, "must be integer stamp");
12,776✔
4322
         low = MAX(low, rt->u.intg.low);
12,776✔
4323
         high = MIN(high, rt->u.intg.high);
12,776✔
4324
      }
4325

4326
      vstamp_t *bt = vcode_stamp_data(stamp);
52,865✔
4327
      if (bt != NULL) {
52,865✔
4328
         VCODE_ASSERT(bt->kind == VCODE_STAMP_INT, "must be integer stamp");
22,157✔
4329
         low = MAX(low, bt->u.intg.low);
22,157✔
4330
         high = MIN(high, bt->u.intg.high);
22,157✔
4331
      }
4332

4333
      stamp = vstamp_int(low, high);
52,865✔
4334
   }
4335

4336
   op->result = vcode_add_reg(type, stamp);
53,707✔
4337

4338
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
94,611✔
4339
      if (from == allowed[i][0] && to == allowed[i][1])
94,611✔
4340
         return op->result;
4341
   }
4342

UNCOV
4343
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4344
}
4345

4346
void emit_return(vcode_reg_t reg)
55,203✔
4347
{
4348
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
55,203✔
4349
   if (reg != VCODE_INVALID_REG) {
55,203✔
4350
      vcode_add_arg(op, reg);
24,534✔
4351

4352
      const vtype_kind_t rkind = vcode_reg_kind(reg);
24,534✔
4353
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY)
24,534✔
4354
         vcode_heap_allocate(reg);
4,551✔
4355

4356
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
24,534✔
4357
                   || active_unit->kind == VCODE_UNIT_THUNK
4358
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4359
                   "returning value fron non-function unit");
4360
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
24,534✔
4361
                    && rkind == VCODE_TYPE_INT)
4362
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4363
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4364
                       && rkind == VCODE_TYPE_ACCESS),
4365
                   "return value incorrect type");
4366
   }
4367
}
55,203✔
4368

4369
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
9,208✔
4370
                         vcode_reg_t values, vcode_reg_t reject,
4371
                         vcode_reg_t after)
4372
{
4373
   int64_t nconst;
9,208✔
4374
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
9,208✔
4375
      emit_comment("Skip empty waveform");
9✔
4376
      return;
9✔
4377
   }
4378

4379
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
9,199✔
4380
   vcode_add_arg(op, nets);
9,199✔
4381
   vcode_add_arg(op, nnets);
9,199✔
4382
   vcode_add_arg(op, values);
9,199✔
4383
   vcode_add_arg(op, reject);
9,199✔
4384
   vcode_add_arg(op, after);
9,199✔
4385

4386
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
9,199✔
4387
                "sched_waveform target is not signal");
4388
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
9,199✔
4389
                "sched_waveform net count is not offset type");
4390
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
9,199✔
4391
                "signal cannot be values argument for sched_waveform");
4392
}
4393

4394
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
70✔
4395
{
4396
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
70✔
4397
   vcode_add_arg(op, nets);
70✔
4398
   vcode_add_arg(op, nnets);
70✔
4399
   vcode_add_arg(op, values);
70✔
4400

4401
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
70✔
4402
                "force target is not signal");
4403
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
70✔
4404
                "force net count is not offset type");
4405
}
70✔
4406

4407
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
42✔
4408
{
4409
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
42✔
4410
   vcode_add_arg(op, nets);
42✔
4411
   vcode_add_arg(op, nnets);
42✔
4412

4413
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
42✔
4414
                "release target is not signal");
4415
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
42✔
4416
                "release net count is not offset type");
4417
}
42✔
4418

4419
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
24✔
4420
                     vcode_reg_t after)
4421
{
4422
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
24✔
4423
   vcode_add_arg(op, nets);
24✔
4424
   vcode_add_arg(op, nnets);
24✔
4425
   vcode_add_arg(op, reject);
24✔
4426
   vcode_add_arg(op, after);
24✔
4427

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

4434
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
32,717✔
4435
{
4436
   int64_t tconst;
32,717✔
4437
   if (vcode_reg_const(test, &tconst)) {
32,717✔
4438
      emit_jump(!!tconst ? btrue : bfalse);
3,838✔
4439
      return;
1,958✔
4440
   }
4441

4442
   op_t *op = vcode_add_op(VCODE_OP_COND);
30,759✔
4443
   vcode_add_arg(op, test);
30,759✔
4444
   vcode_add_target(op, btrue);
30,759✔
4445
   vcode_add_target(op, bfalse);
30,759✔
4446

4447
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
30,759✔
4448
                "cond test is not a bool");
4449
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
30,759✔
4450
                "invalid cond targets");
4451
}
4452

4453
vcode_reg_t emit_neg(vcode_reg_t lhs)
6,971✔
4454
{
4455
   int64_t lconst;
6,971✔
4456
   if (vcode_reg_const(lhs, &lconst))
6,971✔
UNCOV
4457
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4458

4459
   op_t *op = vcode_add_op(VCODE_OP_NEG);
6,971✔
4460
   vcode_add_arg(op, lhs);
6,971✔
4461
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
6,971✔
4462

4463
   return op->result;
6,971✔
4464
}
4465

4466
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
467✔
4467
{
4468
   int64_t lconst;
467✔
4469
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
467✔
UNCOV
4470
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4471

4472
   reg_t *lhs_r = vcode_reg_data(lhs);
467✔
4473

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

4478
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
257✔
4479
   vcode_add_arg(op, lhs);
257✔
4480
   vcode_add_arg(op, locus);
257✔
4481

4482
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
257✔
4483
                "locus argument to trap neg must be a debug locus");
4484
   VCODE_ASSERT(vtype_kind(lhs_r->type) == VCODE_TYPE_INT,
257✔
4485
                "trapping neg may only be used with integer types");
4486

4487
   return (op->result = vcode_add_reg(lhs_r->type, VCODE_INVALID_STAMP));
257✔
4488
}
4489

4490
vcode_reg_t emit_abs(vcode_reg_t lhs)
686✔
4491
{
4492
   int64_t lconst;
686✔
4493
   if (vcode_reg_const(lhs, &lconst))
686✔
4494
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4495

4496
   op_t *op = vcode_add_op(VCODE_OP_ABS);
685✔
4497
   vcode_add_arg(op, lhs);
685✔
4498
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
685✔
4499

4500
   return op->result;
685✔
4501
}
4502

4503
void emit_comment(const char *fmt, ...)
77,758✔
4504
{
4505
#ifndef NDEBUG
4506
   va_list ap;
77,758✔
4507
   va_start(ap, fmt);
77,758✔
4508

4509
   char *buf = xvasprintf(fmt, ap);
77,758✔
4510
   for (char *p = buf + strlen(buf) - 1;
77,758✔
4511
        p >= buf && isspace_iso88591(*p); p--)
77,758✔
UNCOV
4512
      *p = '\0';
×
4513

4514
   vcode_add_op(VCODE_OP_COMMENT)->comment = buf;
77,758✔
4515
   va_end(ap);
77,758✔
4516
#endif
4517
}
77,758✔
4518

4519
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
18,386✔
4520
                        vcode_reg_t rfalse)
4521
{
4522
   int64_t tconst;
18,386✔
4523
   if (vcode_reg_const(test, &tconst))
18,386✔
4524
      return !!tconst ? rtrue : rfalse;
4,709✔
4525
   else if (rtrue == rfalse)
13,677✔
4526
      return rtrue;
4527

4528
   // Find a previous identical select
4529
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
297,095✔
4530
      if (other->args.items[0] == test && other->args.items[1] == rtrue
10,863✔
4531
          && other->args.items[2] == rfalse)
649✔
4532
         return other->result;
556✔
4533
   }
4534

4535
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
12,946✔
4536
   vcode_add_arg(op, test);
12,946✔
4537
   vcode_add_arg(op, rtrue);
12,946✔
4538
   vcode_add_arg(op, rfalse);
12,946✔
4539
   op->result = vcode_add_reg(vcode_reg_type(rtrue), VCODE_INVALID_STAMP);
12,946✔
4540

4541
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
12,946✔
4542
                "select test must have bool type");
4543
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
12,946✔
4544
                "select arguments are not the same type");
4545

4546
   return op->result;
12,946✔
4547
}
4548

4549
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
442✔
4550
{
4551
   switch (op) {
442✔
4552
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
45✔
4553
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
349✔
4554
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
12✔
4555
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
12✔
4556
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
12✔
4557
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
12✔
UNCOV
4558
   default:
×
4559
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
4560
   }
4561
}
4562

4563
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
7,415✔
4564
{
4565
   vcode_type_t vtbool = vtype_bool();
7,415✔
4566

4567
   int64_t lconst, rconst;
7,415✔
4568
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
7,415✔
4569
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
7,415✔
4570
   if (l_is_const && r_is_const) {
7,415✔
4571
      switch (op) {
6✔
UNCOV
4572
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
UNCOV
4573
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
UNCOV
4574
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
×
4575
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
6✔
UNCOV
4576
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
UNCOV
4577
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
UNCOV
4578
      default:
×
4579
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4580
      }
4581
   }
4582
   else if (l_is_const)
7,409✔
4583
      return emit_logical_identity(op, rhs, !!lconst);
342✔
4584
   else if (r_is_const)
7,067✔
4585
      return emit_logical_identity(op, lhs, !!rconst);
100✔
4586
   else if (lhs == rhs) {
6,967✔
4587
      switch (op) {
27✔
4588
      case VCODE_OP_AND:
4589
      case VCODE_OP_OR:
4590
         return lhs;
4591
      case VCODE_OP_NAND:
6✔
4592
      case VCODE_OP_NOR:
4593
         return emit_not(lhs);
6✔
4594
      case VCODE_OP_XOR:
3✔
4595
         return emit_const(vtbool, 0);
3✔
UNCOV
4596
      case VCODE_OP_XNOR:
×
UNCOV
4597
         return emit_const(vtbool, 1);
×
UNCOV
4598
      default:
×
4599
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4600
      }
4601
   }
4602

4603
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
6,940✔
4604

4605
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
6,940✔
4606
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4607
                "arguments to %s are not boolean", vcode_op_string(op));
4608

4609
   return result;
4610
}
4611

4612
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
2,418✔
4613
{
4614
   return emit_logical(VCODE_OP_OR, lhs, rhs);
2,418✔
4615
}
4616

4617
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
4,761✔
4618
{
4619
   return emit_logical(VCODE_OP_AND, lhs, rhs);
4,761✔
4620
}
4621

4622
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
52✔
4623
{
4624
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
52✔
4625
}
4626

4627
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
53✔
4628
{
4629
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
53✔
4630
}
4631

4632
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
73✔
4633
{
4634
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
73✔
4635
}
4636

4637
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
58✔
4638
{
4639
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
58✔
4640
}
4641

4642
vcode_reg_t emit_not(vcode_reg_t arg)
2,502✔
4643
{
4644
   int64_t cval;
2,502✔
4645
   if (vcode_reg_const(arg, &cval))
2,502✔
4646
      return emit_const(vtype_bool(), !cval);
27✔
4647

4648
   op_t *op = vcode_add_op(VCODE_OP_NOT);
2,475✔
4649
   vcode_add_arg(op, arg);
2,475✔
4650

4651
   vcode_type_t vtbool = vtype_bool();
2,475✔
4652
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
2,475✔
4653
                "argument to not is not boolean");
4654

4655
   return (op->result = vcode_add_reg(vtbool, VCODE_INVALID_STAMP));
2,475✔
4656
}
4657

4658
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
46,844✔
4659
{
4660
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,730,929✔
4661
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
155,900✔
4662
         bool match = true;
4663
         for (int i = 0; match && i < ndims; i++) {
22,394✔
4664
            match = other->args.items[i*3 + 1] == dims[i].left
11,229✔
4665
               && other->args.items[i*3 + 2] == dims[i].right
9,034✔
4666
               && other->args.items[i*3 + 3] == dims[i].dir;
19,996✔
4667
         }
4668
         if (match)
11,165✔
4669
            return other->result;
8,703✔
4670
      }
4671
   }
4672

4673
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
38,141✔
4674
   vcode_add_arg(op, data);
38,141✔
4675
   for (int i = 0; i < ndims; i++) {
76,940✔
4676
      vcode_add_arg(op, dims[i].left);
38,799✔
4677
      vcode_add_arg(op, dims[i].right);
38,799✔
4678
      vcode_add_arg(op, dims[i].dir);
38,799✔
4679
   }
4680

4681
   vcode_type_t ptr_type = vcode_reg_type(data);
38,141✔
4682
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
38,141✔
4683
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
38,141✔
4684
                "wrapped data is not pointer or signal");
4685

4686
#ifdef DEBUG
4687
   for (int i = 0; i < ndims; i++) {
76,940✔
4688
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
38,799✔
4689
                   "dimension %d left bound must be scalar", i + 1);
4690
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
38,799✔
4691
                   "dimension %d right bound must be scalar", i + 1);
4692
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
38,799✔
4693
                   "dimension %d direction must be bool", i + 1);
4694
   }
4695
#endif
4696

4697
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
76,282✔
4698
      ? vtype_pointed(ptr_type) : ptr_type;
38,141✔
4699

4700
   op->result = vcode_add_reg(vtype_uarray(ndims, elem), vcode_reg_stamp(data));
38,141✔
4701

4702
   return op->result;
38,141✔
4703
}
4704

4705
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
103,375✔
4706
                                  vcode_reg_t array, unsigned dim,
4707
                                  unsigned arg_index)
4708
{
4709
   // Reuse any previous operation in this block with the same arguments
4710
   VCODE_FOR_EACH_OP(other) {
1,177,142✔
4711
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,132,358✔
4712
          && (rtype == VCODE_INVALID_TYPE
23,567✔
4713
              || vtype_eq(rtype, vcode_reg_type(other->result))))
10,223✔
4714
         return other->result;
23,567✔
4715
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,108,791✔
4716
         return other->args.items[1 + (dim * 3) + arg_index];
35,024✔
4717
   }
4718

4719
   op_t *op = vcode_add_op(o);
44,784✔
4720
   vcode_add_arg(op, array);
44,784✔
4721
   op->dim = dim;
44,784✔
4722

4723
   vcode_type_t atype = vcode_reg_type(array);
44,784✔
4724
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
44,784✔
4725
                "cannot use %s with non-uarray type", vcode_op_string(o));
4726

4727
   vtype_t *vt = vcode_type_data(atype);
44,784✔
4728
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
44,784✔
4729

4730
   if (rtype == VCODE_INVALID_TYPE)
44,784✔
4731
      rtype = vtype_offset();
28,917✔
4732

4733
   return (op->result = vcode_add_reg(rtype, VCODE_INVALID_STAMP));
44,784✔
4734
}
4735

4736
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
38,128✔
4737
{
4738
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
38,128✔
4739
                         array, dim, 0);
4740
}
4741

4742
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
27,381✔
4743
{
4744
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
27,381✔
4745
                         array, dim, 1);
4746
}
4747

4748
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
37,866✔
4749
{
4750
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
37,866✔
4751
                         array, dim, 2);
4752
}
4753

4754
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
46,084✔
4755
{
4756
   VCODE_FOR_EACH_OP(other) {
669,266✔
4757
      if (other->kind == VCODE_OP_UARRAY_LEN) {
647,604✔
4758
         if (other->args.items[0] == array && other->dim == dim)
41,054✔
4759
            return other->result;
9,611✔
4760
      }
4761
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
606,550✔
4762
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
14,811✔
4763
                      "array dimension %d out of bounds", dim);
4764

4765
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
14,811✔
4766
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
14,811✔
4767
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
14,811✔
4768
         return emit_range_length(left_reg, right_reg, dir_reg);
14,811✔
4769
      }
4770
   }
4771

4772
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
21,662✔
4773
   vcode_add_arg(op, array);
21,662✔
4774
   op->dim = dim;
21,662✔
4775

4776
   vcode_type_t atype = vcode_reg_type(array);
21,662✔
4777
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
21,662✔
4778
                "cannot use uarray len with non-uarray type");
4779

4780
   vtype_t *vt = vcode_type_data(atype);
21,662✔
4781
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
21,662✔
4782

4783
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
21,662✔
4784

4785
   return op->result;
21,662✔
4786
}
4787

4788
vcode_reg_t emit_unwrap(vcode_reg_t array)
35,585✔
4789
{
4790
   VCODE_FOR_EACH_OP(other) {
1,546,419✔
4791
      if (other->kind == VCODE_OP_WRAP && other->result == array)
1,521,080✔
4792
         return other->args.items[0];
8,499✔
4793
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
1,512,581✔
4794
         return other->result;
1,747✔
4795
   }
4796

4797
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
25,339✔
4798
   vcode_add_arg(op, array);
25,339✔
4799

4800
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
25,339✔
4801
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
25,339✔
4802
                "unwrap can only only be used with uarray types");
4803

4804
   vcode_type_t elem = vt->elem;
25,339✔
4805

4806
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
25,339✔
4807
      ? elem : vtype_pointer(elem);
25,339✔
4808

4809
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
25,339✔
4810
}
4811

4812
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
29,534✔
4813
                            vcode_reg_t dir)
4814
{
4815
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
1,431,399✔
UNCOV
4816
      if (other->args.items[0] == left
×
UNCOV
4817
          && other->args.items[1] == right
×
UNCOV
4818
          && other->args.items[2] == dir)
×
UNCOV
4819
         return other->result;
×
4820
   }
4821

4822
   int64_t dir_const, l_low, l_high, r_low, r_high;
29,534✔
4823
   if (vcode_reg_const(dir, &dir_const)
29,534✔
4824
       && vcode_reg_bounds(left, &l_low, &l_high)
26,537✔
4825
       && vcode_reg_bounds(right, &r_low, &r_high)) {
26,537✔
4826

4827
      if (dir_const == RANGE_TO && l_low > r_high)
26,537✔
4828
         return emit_const(vtype_bool(), 1);
65✔
4829
      else if (dir_const == RANGE_TO && l_high <= r_low)
26,472✔
4830
         return emit_const(vtype_bool(), 0);
18,419✔
4831
      else if (dir_const == RANGE_DOWNTO && r_low > l_high)
8,053✔
4832
         return emit_const(vtype_bool(), 1);
619✔
4833
      else if (dir_const == RANGE_DOWNTO && r_high <= l_low)
7,434✔
4834
         return emit_const(vtype_bool(), 0);
1,890✔
4835
      else if (dir_const == RANGE_TO)
5,544✔
4836
         return emit_cmp(VCODE_CMP_GT, left, right);
2,831✔
4837
      else
4838
         return emit_cmp(VCODE_CMP_GT, right, left);
2,713✔
4839
   }
4840

4841
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
2,997✔
4842
   vcode_add_arg(op, left);
2,997✔
4843
   vcode_add_arg(op, right);
2,997✔
4844
   vcode_add_arg(op, dir);
2,997✔
4845

4846
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
2,997✔
4847
                "range left and right have different types");
4848
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
2,997✔
4849
                "dir argument to range length is not int");
4850

4851
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
2,997✔
4852
}
4853

4854
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
14,849✔
4855
                              vcode_reg_t dir)
4856
{
4857
   vcode_reg_t left_array = VCODE_INVALID_REG,
14,849✔
4858
      right_array = VCODE_INVALID_REG,
14,849✔
4859
      dir_array = VCODE_INVALID_REG;
14,849✔
4860
   int left_dim = -1, right_dim = -1, dir_dim = -1;
14,849✔
4861

4862
   VCODE_FOR_EACH_OP(other) {
292,084✔
4863
      if (other->kind == VCODE_OP_RANGE_LENGTH
282,795✔
4864
          && other->args.items[0] == left
7,889✔
4865
          && other->args.items[1] == right
5,877✔
4866
          && other->args.items[2] == dir)
5,560✔
4867
         return other->result;
5,560✔
4868
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
277,235✔
4869
         left_array = other->args.items[0];
362✔
4870
         left_dim = other->dim;
362✔
4871
      }
4872
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
276,873✔
4873
         right_array = other->args.items[0];
362✔
4874
         right_dim = other->dim;
362✔
4875
      }
4876
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
276,511✔
4877
         dir_array = other->args.items[0];
706✔
4878
         dir_dim = other->dim;
706✔
4879
      }
4880
   }
4881

4882
   if (left_array != VCODE_INVALID_REG && left_array == right_array
9,289✔
4883
       && right_array == dir_array && left_dim == right_dim
362✔
4884
       && right_dim == dir_dim)
362✔
4885
      return emit_uarray_len(left_array, left_dim);
362✔
4886

4887
   int64_t lconst, rconst, dconst;
8,927✔
4888
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
8,927✔
4889
       && vcode_reg_const(right, &rconst)) {
4,889✔
4890

4891
      int64_t diff;
1,846✔
4892
      if (dconst == RANGE_TO)
1,846✔
4893
         diff = rconst - lconst;
1,549✔
4894
      else
4895
         diff = lconst - rconst;
297✔
4896

4897
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
1,846✔
4898
   }
4899

4900
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
7,081✔
4901
   vcode_add_arg(op, left);
7,081✔
4902
   vcode_add_arg(op, right);
7,081✔
4903
   vcode_add_arg(op, dir);
7,081✔
4904

4905
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
7,081✔
4906
                "range left and right have different types");
4907
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
7,081✔
4908
                "dir argument to range length is not int");
4909

4910
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
7,081✔
4911

4912
   return op->result;
7,081✔
4913
}
4914

4915
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
54,201✔
4916
{
4917
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
493,742✔
4918
      if (other->hops == hops && other->address == var)
66,263✔
4919
         return other->result;
10,862✔
4920
   }
4921

4922
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
43,339✔
4923
   op->hops    = hops;
43,339✔
4924
   op->address = var;
43,339✔
4925

4926
   VCODE_ASSERT(hops > 0, "invalid hop count");
43,339✔
4927

4928
   vcode_unit_t vu = active_unit;
43,339✔
4929
   for (int i = 0; i < hops; i++) {
95,967✔
4930
      vu = vu->context;
52,628✔
4931
      VCODE_ASSERT(vu, "hop count is greater than depth");
52,628✔
4932
   }
4933

4934
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
43,339✔
4935

4936
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
43,339✔
4937

4938
   return op->result;
43,339✔
4939
}
4940

4941
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
16,214✔
4942
                             vcode_reg_t size, vcode_reg_t value,
4943
                             vcode_reg_t flags, vcode_reg_t locus,
4944
                             vcode_reg_t offset)
4945
{
4946
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
16,214✔
4947
   vcode_add_arg(op, count);
16,214✔
4948
   vcode_add_arg(op, size);
16,214✔
4949
   vcode_add_arg(op, value);
16,214✔
4950
   vcode_add_arg(op, flags);
16,214✔
4951
   vcode_add_arg(op, locus);
16,214✔
4952
   if (offset != VCODE_INVALID_REG)
16,214✔
4953
      vcode_add_arg(op, offset);
5,736✔
4954

4955
   vcode_type_t vtype = vcode_reg_type(value);
16,214✔
4956
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
16,214✔
4957
   VCODE_ASSERT(vtype_eq(vtype, type)
16,214✔
4958
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4959
                "init signal value type does not match signal type");
4960
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
16,214✔
4961
                "locus argument to init signal must be a debug locus");
4962
   VCODE_ASSERT(offset == VCODE_INVALID_REG
16,214✔
4963
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4964
                "init signal offset argument must have pointer type");
4965

4966
   vcode_type_t stype = vtype_signal(type);
16,214✔
4967
   return (op->result = vcode_add_reg(stype, VCODE_INVALID_STAMP));
16,214✔
4968
}
4969

4970
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
3,388✔
4971
{
4972
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
3,388✔
4973
   vcode_add_arg(op, signal);
3,388✔
4974
   vcode_add_arg(op, resolution);
3,388✔
4975

4976
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
3,388✔
4977
                "signal argument has wrong type");
4978

4979
   vcode_type_t rtype = vcode_reg_type(resolution);
3,388✔
4980
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
3,388✔
4981
                "resolution wrapper argument must be pointer");
4982
   VCODE_ASSERT(vtype_kind(vtype_pointed(rtype)) == VCODE_TYPE_RESOLUTION,
3,388✔
4983
                "resolution wrapper argument has wrong type");
4984
}
3,388✔
4985

4986
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
75✔
4987
                                 vcode_reg_t size, vcode_reg_t locus,
4988
                                 vcode_reg_t kind, vcode_reg_t closure,
4989
                                 vcode_reg_t delay)
4990
{
4991
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
75✔
4992
   vcode_add_arg(op, count);
75✔
4993
   vcode_add_arg(op, size);
75✔
4994
   vcode_add_arg(op, locus);
75✔
4995
   vcode_add_arg(op, kind);
75✔
4996
   vcode_add_arg(op, closure);
75✔
4997
   vcode_add_arg(op, delay);
75✔
4998

4999
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
75✔
5000
                "count argument to implicit signal is not offset");
5001
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
75✔
5002
                "kind argument to implicit signal is not offset");
5003
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
75✔
5004
                "closure argument to implicit signal is not a closure");
5005
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
75✔
5006
                "locus argument to implicit signal must be a debug locus");
5007
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
75✔
5008
                "delay argument to implicit signal must be time");
5009

5010
   vcode_type_t stype = vtype_signal(type);
75✔
5011
   return (op->result = vcode_add_reg(stype, VCODE_INVALID_REG));
75✔
5012
}
5013

5014
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
5,440✔
5015
{
5016
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
5,440✔
5017
   vcode_add_arg(op, src);
5,440✔
5018
   vcode_add_arg(op, dst);
5,440✔
5019
   vcode_add_arg(op, count);
5,440✔
5020

5021
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
5,440✔
5022
                "src argument to map signal is not a signal");
5023
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
5,440✔
5024
                "dst argument to map signal is not a signal");
5025
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5,440✔
5026
                "count argument type to map signal is not offset");
5027
}
5,440✔
5028

5029
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
200✔
5030
{
5031
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
200✔
5032
   vcode_add_arg(op, src);
200✔
5033
   vcode_add_arg(op, dst);
200✔
5034
   vcode_add_arg(op, count);
200✔
5035

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

5042
void emit_map_implicit(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
57✔
5043
{
5044
   op_t *op = vcode_add_op(VCODE_OP_MAP_IMPLICIT);
57✔
5045
   vcode_add_arg(op, src);
57✔
5046
   vcode_add_arg(op, dst);
57✔
5047
   vcode_add_arg(op, count);
57✔
5048

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

5057
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
7,239✔
5058
{
5059
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
91,689✔
5060
      if (other->args.items[0] == target && other->args.items[1] == count)
12,124✔
5061
         return;
5062
   }
5063

5064
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
7,236✔
5065
   vcode_add_arg(op, target);
7,236✔
5066
   vcode_add_arg(op, count);
7,236✔
5067

5068
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
7,236✔
5069
                "target argument to drive signal is not a signal");
5070
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
7,236✔
5071
                "count argument type to drive signal is not offset");
5072
}
5073

5074
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
530✔
5075
                          vcode_reg_t count, vcode_reg_t reject,
5076
                          vcode_reg_t after)
5077
{
5078
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
530✔
5079
   vcode_add_arg(op, target);
530✔
5080
   vcode_add_arg(op, source);
530✔
5081
   vcode_add_arg(op, count);
530✔
5082
   vcode_add_arg(op, reject);
530✔
5083
   vcode_add_arg(op, after);
530✔
5084

5085
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
530✔
5086
                "target argument to transfer signal is not a signal");
5087
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
530✔
5088
                "count argument type to transfer signal is not offset");
5089
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
530✔
5090
                "source argument to transfer signal is not a signal");
5091
}
530✔
5092

5093
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
5,151✔
5094
                                    vcode_reg_t nlits)
5095
{
5096
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
84,332✔
5097
      if (other->args.items[0] == closure && other->args.items[1] == nlits)
11,219✔
UNCOV
5098
         return other->result;
×
5099
   }
5100

5101
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
5,151✔
5102
                "first argument to resolution wrapper must be closure");
5103

5104
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
5,151✔
5105
   vcode_add_arg(op, closure);
5,151✔
5106
   vcode_add_arg(op, nlits);
5,151✔
5107

5108
   return (op->result = vcode_add_reg(vtype_resolution(type),
5,151✔
5109
                                      VCODE_INVALID_STAMP));
5110
}
5111

5112
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t rtype)
5,448✔
5113
{
5114
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
85,484✔
5115
      if (other->func == func && other->args.items[0] == context)
11,390✔
UNCOV
5116
         return other->result;
×
5117
   }
5118

5119
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
5,448✔
5120
   vcode_add_arg(op, context);
5,448✔
5121
   op->func = func;
5,448✔
5122

5123
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5,448✔
5124
                "invalid closure context argument");
5125

5126
   return (op->result = vcode_add_reg(vtype_closure(rtype),
5,448✔
5127
                                      VCODE_INVALID_STAMP));
5128
}
5129

5130
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
35,358✔
5131
{
5132
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
68,341✔
5133
      if (other->func == name)
28,858✔
5134
         return other->result;
13,513✔
5135
   }
5136

5137
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
21,845✔
5138
   op->func = name;
21,845✔
5139
   if (context != VCODE_INVALID_REG)
21,845✔
5140
      vcode_add_arg(op, context);
190✔
5141

5142
   VCODE_ASSERT(context == VCODE_INVALID_REG
21,845✔
5143
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5144
                "invalid protected init context argument");
5145
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
21,845✔
5146
                || active_unit->kind == VCODE_UNIT_PACKAGE
5147
                || active_unit->kind == VCODE_UNIT_THUNK,
5148
                "cannot use package init here");
5149
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
21,845✔
5150

5151
   return (op->result = vcode_add_reg(vtype_context(name),
21,845✔
5152
                                      VCODE_INVALID_STAMP));
5153
}
5154

5155
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
544✔
5156
                                vcode_reg_t path_name, vcode_reg_t inst_name)
5157
{
5158
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
544✔
5159
   vcode_add_arg(op, context);
544✔
5160
   op->func = vtype_name(type);
544✔
5161

5162
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
544✔
5163
      vcode_add_arg(op, path_name);
414✔
5164
      vcode_add_arg(op, inst_name);
414✔
5165

5166
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
414✔
5167
                   "path name argument must be uarray");
5168
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
414✔
5169
                   "inst name argument must be uarray");
5170
   }
5171

5172
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
544✔
5173
                "protected init type must be context");
5174
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
544✔
5175
                "invalid protected init context argument");
5176

5177
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
544✔
5178
}
5179

5180
void emit_process_init(ident_t name, vcode_reg_t locus)
117✔
5181
{
5182
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
117✔
5183
   vcode_add_arg(op, locus);
117✔
5184
   op->func = name;
117✔
5185

5186
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
117✔
5187
                "locus argument to process init must be a debug locus");
5188
}
117✔
5189

5190
void emit_protected_free(vcode_reg_t obj)
308✔
5191
{
5192
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
308✔
5193
   vcode_add_arg(op, obj);
308✔
5194

5195
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
308✔
5196
                "protected object type must be context");
5197
}
308✔
5198

5199
vcode_reg_t emit_context_upref(int hops)
19,559✔
5200
{
5201
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
133,207✔
5202
      if (other->hops == hops)
8,731✔
5203
         return other->result;
8,683✔
5204
   }
5205

5206
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
10,876✔
5207
   op->hops = hops;
10,876✔
5208

5209
   VCODE_ASSERT(hops >= 0, "invalid hop count");
10,876✔
5210

5211
   vcode_unit_t vu = active_unit;
10,876✔
5212
   for (int i = 0; i < hops; i++) {
19,129✔
5213
      vu = vu->context;
8,253✔
5214
      VCODE_ASSERT(vu, "hop count is greater than depth");
8,253✔
5215
   }
5216

5217
   return (op->result = vcode_add_reg(vtype_context(vu->name),
10,876✔
5218
                                      VCODE_INVALID_STAMP));
5219
}
5220

5221
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
661✔
5222
                                    vcode_reg_t len)
5223
{
5224
   op_t *op = vcode_add_op(opkind);
661✔
5225
   vcode_add_arg(op, nets);
661✔
5226
   vcode_add_arg(op, len);
661✔
5227

5228
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
661✔
5229
                "argument to %s is not a signal", vcode_op_string(opkind));
5230

5231
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
661✔
5232
}
5233

5234
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
444✔
5235
{
5236
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
444✔
5237
}
5238

5239
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
217✔
5240
{
5241
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
217✔
5242
}
5243

5244
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
37,008✔
5245
{
5246
   // Try scanning backwards through the block for another record ref
5247
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
2,683,014✔
5248
      if (other->args.items[0] == record && other->field == field)
503,382✔
5249
         return other->result;
3,881✔
5250
   }
5251

5252
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
33,127✔
5253
   op->field = field;
33,127✔
5254
   vcode_add_arg(op, record);
33,127✔
5255

5256
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
33,127✔
5257

5258
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
33,127✔
5259
                "argument to record ref must be a pointer");
5260

5261
   vtype_t *rtype = vcode_type_data(rptype->pointed);
33,127✔
5262
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
33,127✔
5263
                "argument must be pointer to record or record signal");
5264

5265
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
33,127✔
5266

5267
   vcode_type_t field_type  = rtype->fields.items[field];
33,127✔
5268
   vcode_type_t result_type = field_type;
33,127✔
5269

5270
   const vtype_kind_t fkind = vtype_kind(field_type);
33,127✔
5271
   if (fkind == VCODE_TYPE_CARRAY)
33,127✔
5272
      result_type = vtype_elem(field_type);
4,559✔
5273
   else if (fkind == VCODE_TYPE_UARRAY)
5274
      result_type = field_type;
5275

5276
   op->result = vcode_add_reg(vtype_pointer(result_type), VCODE_INVALID_STAMP);
33,127✔
5277

5278
   return op->result;
33,127✔
5279
}
5280

5281
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
33,223✔
5282
{
5283
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
1,658,215✔
5284
      if (other->args.items[0] == array && other->args.items[1] == offset)
104,250✔
5285
         return other->result;
1,215✔
5286
   }
5287

5288
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
32,008✔
5289
   vcode_add_arg(op, array);
32,008✔
5290
   vcode_add_arg(op, offset);
32,008✔
5291

5292
   vcode_type_t rtype = vcode_reg_type(array);
32,008✔
5293
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
32,008✔
5294
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5295
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5296
                "argument to array ref must be a pointer or signal");
5297
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
32,008✔
5298
                "array ref offset argument must have offset type");
5299

5300
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
32,008✔
5301
}
5302

5303
vcode_reg_t emit_table_ref(vcode_reg_t array, vcode_reg_t stride,
725✔
5304
                           const vcode_reg_t *args, int nargs)
5305
{
5306
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_TABLE_REF) {
21,104✔
5307
      if (other->args.items[0] != array || other->args.items[1] != stride)
851✔
5308
         continue;
598✔
5309
      else if (other->args.count != nargs + 2)
253✔
UNCOV
5310
         continue;
×
5311

5312
      bool match = true;
5313
      for (int i = 0; i < nargs; i++)
649✔
5314
         match &= (other->args.items[i + 2] == args[i]);
396✔
5315

5316
      if (match)
253✔
5317
         return other->result;
26✔
5318
   }
5319

5320
   op_t *op = vcode_add_op(VCODE_OP_TABLE_REF);
699✔
5321
   vcode_add_arg(op, array);
699✔
5322
   vcode_add_arg(op, stride);
699✔
5323
   for (int i = 0; i < nargs; i++)
1,745✔
5324
      vcode_add_arg(op, args[i]);
1,046✔
5325

5326
   vcode_type_t rtype = vcode_reg_type(array);
699✔
5327
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER
699✔
5328
                && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY,
5329
                "argument to table ref must be a pointer or signal");
5330
   VCODE_ASSERT(vcode_reg_kind(stride) == VCODE_TYPE_OFFSET,
699✔
5331
                "table ref stride argument must have offset type");
5332

5333
   for (int i = 0; i < nargs; i++)
1,745✔
5334
      VCODE_ASSERT(vtype_is_integral(vcode_reg_type(args[i])),
1,046✔
5335
                   "table ref indices must be integral");
5336

5337
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
699✔
5338
}
5339

5340
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
30,306✔
5341
{
5342
   int64_t cconst;
30,306✔
5343
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
30,306✔
5344
       && cconst == 0)
20,402✔
5345
      return;
5,370✔
5346
   else if (dest == src)
29,552✔
5347
      return;
5348

5349
   op_t *op = vcode_add_op(VCODE_OP_COPY);
24,936✔
5350
   vcode_add_arg(op, dest);
24,936✔
5351
   vcode_add_arg(op, src);
24,936✔
5352
   if (count != VCODE_INVALID_REG)
24,936✔
5353
      vcode_add_arg(op, count);
23,360✔
5354

5355
   vcode_type_t dtype = vcode_reg_type(dest);
24,936✔
5356
   vcode_type_t stype = vcode_reg_type(src);
24,936✔
5357

5358
   vtype_kind_t dkind = vtype_kind(dtype);
24,936✔
5359
   vtype_kind_t skind = vtype_kind(stype);
24,936✔
5360

5361
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
24,936✔
5362
                "destination type is not a pointer or access");
5363
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
24,936✔
5364
                "source type is not a pointer or access");
5365
   VCODE_ASSERT(vtype_eq(dtype, stype),
24,936✔
5366
                "source and destination types do not match");
5367
   VCODE_ASSERT(count == VCODE_INVALID_REG
24,936✔
5368
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5369
                "count is not offset type");
5370

5371
   op->type = vtype_pointed(dtype);
24,936✔
5372
}
5373

5374
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
4,486✔
5375
{
5376
   VCODE_FOR_EACH_OP(other) {
63,571✔
5377
      if (other->kind == VCODE_OP_CLEAR_EVENT)
59,139✔
5378
         break;
5379
      else if (other->kind == VCODE_OP_SCHED_EVENT
59,091✔
5380
               && other->args.items[0] == nets
2,600✔
5381
               && other->args.items[1] == n_elems)
9✔
5382
         return;
5383
   }
5384

5385
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
4,480✔
5386
   vcode_add_arg(op, nets);
4,480✔
5387
   vcode_add_arg(op, n_elems);
4,480✔
5388

5389
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
4,480✔
5390
                "nets argument to sched event must be signal");
5391
}
5392

5393
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
550✔
5394
{
5395
   VCODE_FOR_EACH_OP(other) {
2,524✔
5396
      if (other->kind == VCODE_OP_SCHED_EVENT)
1,974✔
5397
         break;
5398
      else if (other->kind == VCODE_OP_CLEAR_EVENT
1,974✔
5399
               && other->args.items[0] == nets
39✔
UNCOV
5400
               && other->args.items[1] == n_elems)
×
5401
         return;
5402
   }
5403

5404
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
550✔
5405
   vcode_add_arg(op, nets);
550✔
5406
   vcode_add_arg(op, n_elems);
550✔
5407

5408
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
550✔
5409
                "nets argument to clear event must be signal");
5410
}
5411

5412
void emit_sched_process(vcode_reg_t delay)
5,267✔
5413
{
5414
   op_t *op = vcode_add_op(VCODE_OP_SCHED_PROCESS);
5,267✔
5415
   vcode_add_arg(op, delay);
5,267✔
5416

5417
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
5,267✔
5418
                "delay must have integer type");
5419
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
5,267✔
5420
                || active_unit->kind == VCODE_UNIT_PROCESS,
5421
                "sched process only allowed in process or procedure");
5422
}
5,267✔
5423

5424
void emit_resume(ident_t func)
843✔
5425
{
5426
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
843✔
5427
   op->func = func;
843✔
5428

5429
   block_t *b = &(active_unit->blocks.items[active_block]);
843✔
5430
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
843✔
5431
}
843✔
5432

5433
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
5,513✔
5434
{
5435
   int64_t lconst;
5,513✔
5436
   if (vcode_reg_const(len, &lconst) && lconst == 0)
5,513✔
5437
      return;
32✔
5438

5439
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
5,481✔
5440
   vcode_add_arg(op, ptr);
5,481✔
5441
   vcode_add_arg(op, value);
5,481✔
5442
   vcode_add_arg(op, len);
5,481✔
5443

5444
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
5,481✔
5445
                "target of memset must have pointer type");
5446
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
5,481✔
5447
                "value of memset must have scalar type");
5448
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
5,481✔
5449
                "length of memset must have offset type");
5450
}
5451

5452
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
647✔
5453
               const vcode_block_t *blocks, int ncases)
5454
{
5455
   int64_t cval1, cval2;
647✔
5456
   bool is_const = vcode_reg_const(value, &cval1);
647✔
5457

5458
   for (int i = 0; i < ncases; i++) {
3,699✔
5459
      bool can_fold = false;
3,052✔
5460
      if (cases[i] == value)
3,052✔
5461
         can_fold = true;
5462
      else if (is_const && vcode_reg_const(cases[i], &cval2))
3,052✔
UNCOV
5463
         can_fold = (cval1 == cval2);
×
5464

UNCOV
5465
      if (can_fold) {
×
UNCOV
5466
         emit_jump(blocks[i]);
×
UNCOV
5467
         return;
×
5468
      }
5469
   }
5470

5471
   if (is_const) {
647✔
UNCOV
5472
      emit_jump(def);
×
UNCOV
5473
      return;
×
5474
   }
5475

5476
   op_t *op = vcode_add_op(VCODE_OP_CASE);
647✔
5477
   vcode_add_arg(op, value);
647✔
5478
   vcode_add_target(op, def);
647✔
5479

5480
   for (int i = 0; i < ncases; i++) {
3,699✔
5481
      vcode_add_arg(op, cases[i]);
3,052✔
5482
      vcode_add_target(op, blocks[i]);
3,052✔
5483

5484
#ifdef DEBUG
5485
      for (int j = 0; j < i; j++)
15,623✔
5486
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
12,571✔
5487
#endif
5488
   }
5489
}
5490

5491
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
1,236✔
5492
                    vcode_reg_t kind, vcode_reg_t status)
5493
{
5494
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
1,236✔
5495
   vcode_add_arg(op, file);
1,236✔
5496
   vcode_add_arg(op, name);
1,236✔
5497
   vcode_add_arg(op, length);
1,236✔
5498
   vcode_add_arg(op, kind);
1,236✔
5499
   if (status != VCODE_INVALID_REG)
1,236✔
5500
      vcode_add_arg(op, status);
25✔
5501

5502
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
1,236✔
5503
                "file open first argument must have file pointer type");
5504
}
1,236✔
5505

5506
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
261✔
5507
{
5508
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
261✔
5509
   vcode_add_arg(op, file);
261✔
5510
   vcode_add_arg(op, value);
261✔
5511
   if (length != VCODE_INVALID_REG)
261✔
5512
      vcode_add_arg(op, length);
204✔
5513

5514
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
261✔
5515
                "file write first argument must have file pointer type");
5516
}
261✔
5517

5518
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
90✔
5519
                    vcode_reg_t inlen, vcode_reg_t outlen)
5520
{
5521
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
90✔
5522
   vcode_add_arg(op, file);
90✔
5523
   vcode_add_arg(op, ptr);
90✔
5524
   if (inlen != VCODE_INVALID_REG) {
90✔
5525
      vcode_add_arg(op, inlen);
42✔
5526
      if (outlen != VCODE_INVALID_REG)
42✔
5527
         vcode_add_arg(op, outlen);
33✔
5528
   }
5529

5530
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
90✔
5531
                "file read first argument must have file pointer type");
5532
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
90✔
5533
                "file read pointer argument must have pointer type");
5534
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
90✔
5535
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5536
                "file read outlen argument must have pointer type");
5537
}
90✔
5538

5539
vcode_reg_t emit_null(vcode_type_t type)
12,676✔
5540
{
5541
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
254,700✔
5542
      if (vtype_eq(vcode_reg_type(other->result), type))
7,553✔
5543
         return other->result;
4,014✔
5544
   }
5545

5546
   op_t *op = vcode_add_op(VCODE_OP_NULL);
8,662✔
5547
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
8,662✔
5548

5549
   vtype_kind_t kind = vtype_kind(type);
8,662✔
5550
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
8,662✔
5551
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5552
                "null type must be file, access, context, or pointer");
5553

5554
   return op->result;
5555
}
5556

5557
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
645✔
5558
{
5559
   op_t *op = vcode_add_op(VCODE_OP_NEW);
645✔
5560
   if (length != VCODE_INVALID_REG)
645✔
5561
      vcode_add_arg(op, length);
554✔
5562

5563
   op->result = vcode_add_reg(vtype_access(type), VCODE_INVALID_STAMP);
645✔
5564

5565
   vtype_kind_t kind = vtype_kind(type);
645✔
5566
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
645✔
5567
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5568
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5569
                "new type must be int, real, record, access, or uarray");
5570
   VCODE_ASSERT(length == VCODE_INVALID_REG
645✔
5571
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5572
                "new length must have offset type");
5573

5574
   return op->result;
645✔
5575
}
5576

5577
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
2,917✔
5578
{
5579
   VCODE_FOR_EACH_OP(other) {
119,660✔
5580
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
117,487✔
5581
         return;
5582
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
117,069✔
5583
         return;
5584
   }
5585

5586
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
2,173✔
5587
   vcode_add_arg(op, ptr);
2,173✔
5588
   vcode_add_arg(op, locus);
2,173✔
5589

5590
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
2,173✔
5591
                "null check argument must be an access");
5592
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,173✔
5593
                "locus argument to null check must be a debug locus");
5594
}
5595

5596
void emit_deallocate(vcode_reg_t ptr)
341✔
5597
{
5598
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
341✔
5599
   vcode_add_arg(op, ptr);
341✔
5600

5601
   vcode_type_t ptype = vcode_reg_type(ptr);
341✔
5602
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
341✔
5603
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5604
                "deallocate argument must be pointer to access");
5605
}
341✔
5606

5607
vcode_reg_t emit_all(vcode_reg_t reg)
3,562✔
5608
{
5609
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
167,406✔
5610
      if (other->args.items[0] == reg)
10,252✔
5611
         return other->result;
744✔
5612
   }
5613

5614
   op_t *op = vcode_add_op(VCODE_OP_ALL);
2,818✔
5615
   vcode_add_arg(op, reg);
2,818✔
5616

5617
   vcode_type_t vtype = vcode_reg_type(reg);
2,818✔
5618

5619
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
2,818✔
5620
                "all argument must be an access");
5621

5622
   vcode_type_t pointed = vtype_pointed(vtype);
2,818✔
5623
   op->result = vcode_add_reg(vtype_pointer(pointed), vcode_reg_stamp(reg));
2,818✔
5624

5625
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
2,818✔
5626
                "cannot dereference opaque type");
5627

5628
   return op->result;
5629
}
5630

5631
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
13,666✔
5632
{
5633
   block_t *b = &(active_unit->blocks.items[active_block]);
13,666✔
5634
   for (int i = b->ops.count - 1; i >= 0; i--) {
325,555✔
5635
      const op_t *other = &(b->ops.items[i]);
312,450✔
5636
      if (other->kind == kind && other->args.items[0] == sig)
312,450✔
5637
         return other->result;
561✔
5638
   }
5639

5640
   op_t *op = vcode_add_op(kind);
13,105✔
5641
   vcode_add_arg(op, sig);
13,105✔
5642

5643
   vcode_type_t stype = vcode_reg_type(sig);
13,105✔
5644
   op->type = stype;
13,105✔
5645

5646
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
13,105✔
5647
                "argument r%d to resolved is not a signal", sig);
5648

5649
   vcode_type_t rtype = vtype_base(stype);
13,105✔
5650

5651
   const vtype_kind_t rkind = vtype_kind(rtype);
13,105✔
5652
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
13,105✔
UNCOV
5653
      rtype = vtype_elem(rtype);
×
5654

5655
   VCODE_ASSERT(vtype_is_scalar(rtype),
13,105✔
5656
                "resolved signal base type must be scalar");
5657

5658
   op->result = vcode_add_reg(vtype_pointer(rtype), vcode_reg_stamp(sig));
13,105✔
5659

5660
   return op->result;
13,105✔
5661
}
5662

5663
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
13,477✔
5664
{
5665
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
13,477✔
5666
}
5667

5668
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
189✔
5669
{
5670
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
189✔
5671
}
5672

5673
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
42✔
5674
{
5675
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
42✔
5676
   vcode_add_arg(op, signal);
42✔
5677
   if (len != VCODE_INVALID_REG)
42✔
5678
      vcode_add_arg(op, len);
9✔
5679

5680
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
42✔
5681
                "signal argument to last event must have signal type");
5682
   VCODE_ASSERT(len == VCODE_INVALID_REG
42✔
5683
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5684
                "length argument to last event must have offset type");
5685

5686
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
42✔
5687
}
5688

5689
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
45✔
5690
{
5691
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
45✔
5692
   vcode_add_arg(op, signal);
45✔
5693
   if (len != VCODE_INVALID_REG)
45✔
5694
      vcode_add_arg(op, len);
6✔
5695

5696
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
45✔
5697
                "signal argument to last active must have signal type");
5698
   VCODE_ASSERT(len == VCODE_INVALID_REG
45✔
5699
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5700
                "length argument to last active must have offset type");
5701

5702
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
45✔
5703
}
5704

5705
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,296✔
5706
{
5707
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,296✔
5708
   vcode_add_arg(op, signal);
4,296✔
5709
   vcode_add_arg(op, locus);
4,296✔
5710

5711
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,296✔
5712
                "signal argument must have signal type");
5713
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
4,296✔
5714
                "locus argument must have debug locus type");
5715
}
4,296✔
5716

5717
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
36✔
5718
{
5719
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
36✔
5720
   vcode_add_arg(op, signal);
36✔
5721
   vcode_add_arg(op, len);
36✔
5722

5723
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5724
                "signal argument to last active must have signal type");
5725
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
36✔
5726
                "length argument to last active must have offset type");
5727

5728
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
36✔
5729
}
5730

5731
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
120✔
5732
{
5733
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
120✔
5734
   vcode_add_arg(op, signal);
120✔
5735
   if (len != VCODE_INVALID_REG)
120✔
5736
      vcode_add_arg(op, len);
36✔
5737

5738
   vcode_type_t signal_type = vcode_reg_type(signal);
120✔
5739

5740
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
120✔
5741
                "signal argument to last active must have signal type");
5742
   VCODE_ASSERT(len == VCODE_INVALID_REG
120✔
5743
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5744
                "length argument to last active must have offset type");
5745

5746
   vcode_type_t base_type = vtype_base(signal_type);
120✔
5747
   op->result = vcode_add_reg(vtype_pointer(base_type), VCODE_INVALID_STAMP);
120✔
5748

5749
   return op->result;
120✔
5750
}
5751

5752
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
32,950✔
5753
                       vcode_reg_t dim)
5754
{
5755
   if (rlen == llen)
32,950✔
5756
      return;
5757

5758
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
198,614✔
5759
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
2,648✔
5760
         return;
5761
   }
5762

5763
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
7,244✔
5764
   vcode_add_arg(op, llen);
7,244✔
5765
   vcode_add_arg(op, rlen);
7,244✔
5766
   vcode_add_arg(op, locus);
7,244✔
5767
   if (dim != VCODE_INVALID_REG)
7,244✔
5768
      vcode_add_arg(op, dim);
27✔
5769

5770
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
7,244✔
5771
                "locus argument to length check must be a debug locus");
5772
}
5773

5774
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
411✔
5775
{
5776
   int64_t cval;
411✔
5777
   if (vcode_reg_const(exp, &cval) && cval >= 0)
411✔
5778
      return;
47✔
5779

5780
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
4,195✔
5781
      if (other->args.items[0] == exp)
12✔
5782
         return;
5783
   }
5784

5785
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
364✔
5786
   vcode_add_arg(op, exp);
364✔
5787
   vcode_add_arg(op, locus);
364✔
5788

5789
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
364✔
5790
                "exp argument to exponent check must be a integer");
5791
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
364✔
5792
                "locus argument to exponent check must be a debug locus");
5793
}
5794

5795
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
2,488✔
5796
{
5797
   int64_t cval;
2,488✔
5798
   if (vcode_reg_const(denom, &cval) && cval != 0)
2,488✔
5799
      return;
2,397✔
5800

5801
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
2,305✔
5802
      if (other->args.items[0] == denom)
48✔
5803
         return;
5804
   }
5805

5806
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
91✔
5807
   vcode_add_arg(op, denom);
91✔
5808
   vcode_add_arg(op, locus);
91✔
5809

5810
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
91✔
5811
                "denom argument to zero check must be a integer");
5812
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
91✔
5813
                "locus argument to zero check must be a debug locus");
5814
}
5815

5816
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
84,843✔
5817
                                   vcode_reg_t right, vcode_reg_t dir)
5818
{
5819
   int64_t dconst;
84,843✔
5820
   if (!vcode_reg_const(dir, &dconst))
84,843✔
5821
      return false;
5822

5823
   int64_t lconst, rconst;
74,919✔
5824
   if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
74,919✔
5825
      const bool is_null = (dconst == RANGE_TO && lconst > rconst)
50,645✔
5826
         || (dconst == RANGE_DOWNTO && rconst > lconst);
104,345✔
5827

5828
      int64_t low, high;
53,701✔
5829
      if (vcode_reg_bounds(reg, &low, &high)) {
53,701✔
5830
         const bool ok_static =
107,396✔
5831
            (dconst == RANGE_TO && low >= lconst && high <= rconst)
50,642✔
5832
            || (dconst == RANGE_DOWNTO && low >= rconst && high <= lconst)
8,759✔
5833
            || (!is_null && (reg == left || reg == right));
59,701✔
5834

5835
         return ok_static;
53,698✔
5836
      }
5837
   }
5838
   else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
21,218✔
5839
      vstamp_t *lbounds = vcode_stamp_data(vcode_reg_data(left)->stamp);
19,158✔
5840
      vstamp_t *rbounds = vcode_stamp_data(vcode_reg_data(right)->stamp);
19,158✔
5841

5842
      assert(lbounds->kind == VCODE_STAMP_REAL);
19,158✔
5843
      assert(rbounds->kind == VCODE_STAMP_REAL);
19,158✔
5844

5845
      double low, high;
19,158✔
5846

5847
      reg_t *rr = vcode_reg_data(reg);
19,158✔
5848
      vstamp_t *bounds = vcode_stamp_data(rr->stamp);
19,158✔
5849
      if (bounds != NULL) {
19,158✔
5850
         assert(bounds->kind == VCODE_STAMP_REAL);
12,586✔
5851
         low = bounds->u.real.low;
12,586✔
5852
         high = bounds->u.real.high;
12,586✔
5853
      }
5854
      else {
5855
         vtype_t *type = vcode_type_data(rr->type);
6,572✔
5856
         assert(type->kind == VCODE_TYPE_REAL);
6,572✔
5857
         low = type->rlow;
6,572✔
5858
         high = type->rhigh;
6,572✔
5859
      }
5860

5861
      if (isfinite(low) && lbounds->u.real.low == -DBL_MAX
19,158✔
5862
          && isfinite(high) && rbounds->u.real.high == DBL_MAX) {
18,444✔
5863
         // Covers the complete double range so can never overflow
5864
         return true;
18,444✔
5865
      }
5866
   }
5867

5868
   return false;
5869
}
5870

5871
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
85,743✔
5872
                              vcode_reg_t left, vcode_reg_t right,
5873
                              vcode_reg_t dir, vcode_reg_t locus,
5874
                              vcode_reg_t hint)
5875
{
5876
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
3,660,555✔
5877
      if (other->args.items[0] == reg && other->args.items[1] == left
18,271✔
5878
          && other->args.items[2] == right && other->args.items[3] == dir)
1,066✔
5879
         return;
5880
   }
5881

5882
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
84,843✔
5883
      emit_comment("Elided bounds check for r%d", reg);
66,139✔
5884
      return;
66,139✔
5885
   }
5886

5887
   op_t *op = vcode_add_op(kind);
18,704✔
5888
   vcode_add_arg(op, reg);
18,704✔
5889
   vcode_add_arg(op, left);
18,704✔
5890
   vcode_add_arg(op, right);
18,704✔
5891
   vcode_add_arg(op, dir);
18,704✔
5892
   vcode_add_arg(op, locus);
18,704✔
5893
   vcode_add_arg(op, hint);
18,704✔
5894

5895
   VCODE_ASSERT(vtype_is_numeric(vcode_reg_type(reg)),
18,704✔
5896
                "argument to bounds check must be numeric");
5897
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
18,704✔
5898
                "locus argument to bounds check must be a debug locus");
5899
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
18,704✔
5900
                "hint argument to bounds check must be a debug locus");
5901
}
5902

5903
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
22,476✔
5904
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5905
{
5906
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
22,476✔
5907
}
22,476✔
5908

5909
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
63,267✔
5910
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5911
{
5912
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
63,267✔
5913
}
63,267✔
5914

5915
void emit_dir_check(vcode_reg_t reg, vcode_reg_t dir, vcode_reg_t locus)
3,238✔
5916
{
5917
   if (reg == dir)
3,238✔
5918
      return;
5919

5920
   op_t *op = vcode_add_op(VCODE_OP_DIR_CHECK);
2,368✔
5921
   vcode_add_arg(op, reg);
2,368✔
5922
   vcode_add_arg(op, dir);
2,368✔
5923
   vcode_add_arg(op, locus);
2,368✔
5924

5925
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,368✔
5926
                "locus argument to dir check must be a debug locus");
5927
}
5928

5929
void emit_package_scope(vcode_reg_t locus)
45✔
5930
{
5931
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
45✔
5932
   vcode_add_arg(op, locus);
45✔
5933

5934
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5935
                "locus argument to package scope must be a debug locus");
5936
}
45✔
5937

5938
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
654✔
5939
{
5940
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
654✔
5941
   vcode_add_arg(op, locus);
654✔
5942
   op->type = type;
654✔
5943

5944
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
654✔
5945
                "locus argument to array scope must be a debug locus");
5946
}
654✔
5947

5948
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
1,690✔
5949
{
5950
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
1,690✔
5951
   vcode_add_arg(op, locus);
1,690✔
5952
   op->type = type;
1,690✔
5953

5954
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,690✔
5955
                "locus argument to record scope must be a debug locus");
5956
}
1,690✔
5957

5958
void emit_pop_scope(void)
2,389✔
5959
{
5960
   vcode_add_op(VCODE_OP_POP_SCOPE);
2,389✔
5961
}
2,389✔
5962

5963
vcode_reg_t emit_debug_locus(object_t *obj)
175,365✔
5964
{
5965
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
6,643,572✔
5966
      if (other->object == obj)
820,342✔
5967
         return other->result;
18,756✔
5968
   }
5969

5970
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
156,609✔
5971
   op->object = obj;
156,609✔
5972
   op->result = vcode_add_reg(vtype_debug_locus(), VCODE_INVALID_STAMP);
156,609✔
5973

5974
   return op->result;
156,609✔
5975
}
5976

UNCOV
5977
void emit_debug_out(vcode_reg_t reg)
×
5978
{
UNCOV
5979
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
UNCOV
5980
   vcode_add_arg(op, reg);
×
UNCOV
5981
}
×
5982

5983
void emit_cover_stmt(uint32_t tag)
1,300✔
5984
{
5985
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,300✔
5986
   op->tag = tag;
1,300✔
5987
}
1,300✔
5988

5989
void emit_cover_branch(uint32_t tag)
499✔
5990
{
5991
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
499✔
5992
   op->tag = tag;
499✔
5993
}
499✔
5994

5995
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
312✔
5996
{
5997
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
312✔
5998
   vcode_add_arg(op, signal);
312✔
5999
   op->tag = tag;
312✔
6000
}
312✔
6001

6002
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
12✔
6003
{
6004
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
12✔
6005
   vcode_add_arg(op, signal);
12✔
6006
   vcode_add_arg(op, low);
12✔
6007
   op->tag = tag;
12✔
6008
}
12✔
6009

6010
void emit_cover_expr(uint32_t tag)
887✔
6011
{
6012
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
887✔
6013
   op->tag = tag;
887✔
6014
}
887✔
6015

6016
void emit_unreachable(vcode_reg_t locus)
1,360✔
6017
{
6018
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
1,360✔
6019
   if (locus != VCODE_INVALID_REG)
1,360✔
6020
      vcode_add_arg(op, locus);
118✔
6021
}
1,360✔
6022

6023
vcode_reg_t emit_undefined(vcode_type_t type, vcode_stamp_t stamp)
63✔
6024
{
6025
   active_unit->flags |= UNIT_UNDEFINED;
63✔
6026

6027
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
63✔
6028
   op->result = vcode_add_reg(type, stamp);
63✔
6029

6030
   return op->result;
63✔
6031
}
6032

6033
void emit_debug_info(const loc_t *loc)
2,459,629✔
6034
{
6035
   if (!loc_invalid_p(loc))
2,459,629✔
6036
      vcode_block_data()->last_loc = *loc;
2,437,328✔
6037
}
2,459,629✔
6038

6039
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
8,862✔
6040
{
6041
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
309,983✔
6042
      if (other->args.items[0] == context && other->ident == name)
12,156✔
6043
         return other->result;
3,985✔
6044
   }
6045

6046
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
4,877✔
6047
   vcode_add_arg(op, context);
4,877✔
6048
   op->ident = name;
4,877✔
6049

6050
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
4,877✔
6051
                "first argument to link var must be context");
6052

6053
   vcode_stamp_t stamp = VCODE_INVALID_STAMP;
4,877✔
6054

6055
   if (vtype_kind(type) == VCODE_TYPE_CARRAY)
4,877✔
6056
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)), stamp);
612✔
6057
   else
6058
      op->result = vcode_add_reg(vtype_pointer(type), stamp);
4,265✔
6059

6060
   return op->result;
4,877✔
6061
}
6062

6063
vcode_reg_t emit_link_package(ident_t name)
12,929✔
6064
{
6065
   VCODE_FOR_EACH_OP(other) {
466,402✔
6066
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
459,700✔
6067
         return other->result;
5,682✔
6068
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
454,018✔
6069
         return other->result;
545✔
6070
   }
6071

6072
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
6,702✔
6073
   op->ident = name;
6,702✔
6074

6075
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
6,702✔
6076

6077
   vcode_type_t type = vtype_context(name);
6,702✔
6078
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
6,702✔
6079
}
6080

6081
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
849✔
6082
{
6083
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
2,046✔
UNCOV
6084
      if (other->args.items[0] == state)
×
6085
         return;
6086
   }
6087

6088
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
849✔
6089
   vcode_add_arg(op, state);
849✔
6090
   if (strong != VCODE_INVALID_REG)
849✔
6091
      vcode_add_arg(op, strong);
36✔
6092

6093
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
849✔
6094
                "state must have integer type");
6095
   VCODE_ASSERT(strong == VCODE_INVALID_REG
849✔
6096
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
6097
                "strong argument not is not boolean");
6098
}
6099

6100
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
48✔
6101
                               vcode_reg_t locus, vcode_reg_t bounds)
6102
{
6103
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
48✔
6104
   vcode_add_arg(op, value);
48✔
6105
   vcode_add_arg(op, context);
48✔
6106
   vcode_add_arg(op, locus);
48✔
6107
   if (bounds != VCODE_INVALID_REG)
48✔
6108
      vcode_add_arg(op, bounds);
6✔
6109

6110
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
48✔
6111
                "invalid reflect value context argument");
6112
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
48✔
6113
                "locus argument to reflect value must be a debug locus");
6114

6115
   vcode_type_t type = vtype_access(vtype_opaque());
48✔
6116
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
48✔
6117
}
6118

6119
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
42✔
6120
                                 vcode_reg_t bounds)
6121
{
6122
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
6123
   vcode_add_arg(op, context);
42✔
6124
   vcode_add_arg(op, locus);
42✔
6125
   if (bounds != VCODE_INVALID_REG)
42✔
UNCOV
6126
      vcode_add_arg(op, bounds);
×
6127

6128
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
6129
                "invalid reflect value context argument");
6130
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
6131
                "locus argument to reflect value must be a debug locus");
6132

6133
   vcode_type_t type = vtype_access(vtype_opaque());
42✔
6134
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
42✔
6135
}
6136

6137
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
202✔
6138
                                  int nargs)
6139
{
6140
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
202✔
6141
   op->func = func;
202✔
6142

6143
   for (int i = 0; i < nargs; i++)
489✔
6144
      vcode_add_arg(op, args[i]);
287✔
6145

6146
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
202✔
6147
}
6148

6149
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
34✔
6150
{
6151
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
34✔
6152
   vcode_add_arg(op, left);
34✔
6153
   vcode_add_arg(op, right);
34✔
6154

6155
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
34✔
6156
                "or trigger left argument must be trigger");
6157
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
34✔
6158
                "or trigger right argument must be trigger");
6159

6160
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
34✔
6161
}
6162

6163
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
66✔
6164
{
6165
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
66✔
6166
   vcode_add_arg(op, left);
66✔
6167
   vcode_add_arg(op, right);
66✔
6168

6169
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
66✔
6170
                "cmp trigger left argument must be signal");
6171
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
66✔
6172
                "cmp trigger right argument must be integer");
6173

6174
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
66✔
6175
}
6176

6177
void emit_add_trigger(vcode_reg_t trigger)
368✔
6178
{
6179
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
368✔
6180
   vcode_add_arg(op, trigger);
368✔
6181

6182
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
368✔
6183
                "add trigger argument must be trigger");
6184
}
368✔
6185

6186
vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective)
204✔
6187
{
6188
   op_t *op = vcode_add_op(VCODE_OP_PORT_CONVERSION);
204✔
6189
   vcode_add_arg(op, driving);
204✔
6190
   if (effective != VCODE_INVALID_REG && effective != driving)
204✔
6191
      vcode_add_arg(op, effective);
18✔
6192

6193
   VCODE_ASSERT(vcode_reg_kind(driving) == VCODE_TYPE_CLOSURE,
204✔
6194
                "port conversion argument must be a closure");
6195
   VCODE_ASSERT(effective == VCODE_INVALID_REG
204✔
6196
                || vcode_reg_kind(effective) == VCODE_TYPE_CLOSURE,
6197
                "port conversion argument must be a closure");
6198

6199
   return (op->result = vcode_add_reg(vtype_conversion(), VCODE_INVALID_STAMP));
204✔
6200
}
6201

6202
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
180✔
6203
                               vcode_type_t type, vcode_stamp_t stamp,
6204
                               const vcode_reg_t *args, int nargs)
6205
{
6206
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
180✔
6207
   op->type  = type;
180✔
6208
   op->ident = scope;
180✔
6209
   vcode_add_arg(op, locus);
180✔
6210
   for (int i = 0; i < nargs; i++)
210✔
6211
      vcode_add_arg(op, args[i]);
30✔
6212

6213
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
180✔
6214
                "bind external argument must be locus");
6215

6216
   op->result = vcode_add_reg(vtype_pointer(type), VCODE_INVALID_STAMP);
180✔
6217
   vcode_reg_data(op->result)->stamp = stamp;
180✔
6218
   return op->result;
180✔
6219
}
6220

6221
void emit_put_conversion(vcode_reg_t cf, vcode_reg_t target, vcode_reg_t count,
342✔
6222
                         vcode_reg_t values)
6223
{
6224
   op_t *op = vcode_add_op(VCODE_OP_PUT_CONVERSION);
342✔
6225
   vcode_add_arg(op, cf);
342✔
6226
   vcode_add_arg(op, target);
342✔
6227
   vcode_add_arg(op, count);
342✔
6228
   vcode_add_arg(op, values);
342✔
6229

6230
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
342✔
6231
                "put conversion target is not signal");
6232
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
342✔
6233
                "put conversion net count is not offset type");
6234
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
342✔
6235
                "signal cannot be values argument for put conversion");
6236
   VCODE_ASSERT(vcode_reg_kind(cf) == VCODE_TYPE_CONVERSION,
342✔
6237
                "cf argument to put conversion must be conversion function");
6238
}
342✔
6239

6240
void emit_convert_in(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
282✔
6241
{
6242
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_IN);
282✔
6243
   vcode_add_arg(op, conv);
282✔
6244
   vcode_add_arg(op, nets);
282✔
6245
   vcode_add_arg(op, count);
282✔
6246

6247
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
282✔
6248
                "conv argument to convert must be a port conversion");
6249
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
282✔
6250
                "nets argument to convert must be a signal");
6251
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
282✔
6252
                "count argument to convert must be offset");
6253
}
282✔
6254

6255
void emit_convert_out(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
324✔
6256
{
6257
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_OUT);
324✔
6258
   vcode_add_arg(op, conv);
324✔
6259
   vcode_add_arg(op, nets);
324✔
6260
   vcode_add_arg(op, count);
324✔
6261

6262
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
324✔
6263
                "conv argument to convert must be a port conversion");
6264
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
324✔
6265
                "nets argument to convert must be a signal");
6266
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
324✔
6267
                "count argument to convert must be offset");
6268
}
324✔
6269

6270
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
1,011✔
6271
{
6272
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
1,011✔
6273
   vcode_add_arg(op, spec);
1,011✔
6274
   vcode_add_arg(op, length);
1,011✔
6275
   if (locus != VCODE_INVALID_REG)
1,011✔
6276
      vcode_add_arg(op, locus);
834✔
6277

6278
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
1,011✔
6279
                "spec argument to bind foreign must be a pointer");
6280
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
1,011✔
6281
                "length argument to bind foreign must be offset");
6282
   VCODE_ASSERT(locus == VCODE_INVALID_REG
1,011✔
6283
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6284
                "locus argument to bind foreign value must be a debug locus");
6285
}
1,011✔
6286

6287
vcode_reg_t emit_instance_name(vcode_reg_t kind)
767✔
6288
{
6289
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
767✔
6290
   vcode_add_arg(op, kind);
767✔
6291

6292
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
767✔
6293
                "kind argument to instance name must be offset");
6294

6295
   vcode_type_t type = vtype_uarray(1, vtype_char());
767✔
6296
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
767✔
6297
}
6298

6299
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
15,360✔
6300
{
6301
   vcode_state_t state;
15,360✔
6302
   vcode_state_save(&state);
15,360✔
6303

6304
   vcode_select_unit(vu);
15,360✔
6305

6306
   const int nblocks = vcode_count_blocks();
15,360✔
6307
   for (int i = 0; i < nblocks; i++) {
54,773✔
6308
      vcode_select_block(i);
39,413✔
6309

6310
      const int nops = vcode_count_ops();
39,413✔
6311
      for (int op = 0; op < nops; op++) {
653,380✔
6312
         switch (vcode_get_op(op)) {
613,967✔
6313
         case VCODE_OP_LINK_PACKAGE:
2,212✔
6314
            (*fn)(vcode_get_ident(op), ctx);
2,212✔
6315
            break;
2,212✔
6316
         case VCODE_OP_FCALL:
23,884✔
6317
         case VCODE_OP_PCALL:
6318
         case VCODE_OP_CLOSURE:
6319
         case VCODE_OP_PROTECTED_INIT:
6320
         case VCODE_OP_PACKAGE_INIT:
6321
         case VCODE_OP_FUNCTION_TRIGGER:
6322
            (*fn)(vcode_get_func(op), ctx);
23,884✔
6323
            break;
23,884✔
6324
         default:
6325
            break;
6326
         }
6327
      }
6328
   }
6329

6330
   vcode_state_restore(&state);
15,360✔
6331
}
15,360✔
6332

6333
#if VCODE_CHECK_UNIONS
6334
#define OP_USE_COUNT_U0(x)                                              \
6335
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6336
#define OP_USE_COUNT_U1(x)                                              \
6337
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6338
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6339
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6340

6341
__attribute__((constructor))
6342
static void vcode_check_unions(void)
6343
{
6344
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6345
   for (int i = 0; i < 256; i++) {
6346
      assert(OP_USE_COUNT_U0(i) <= 1);
6347
      assert(OP_USE_COUNT_U1(i) <= 1);
6348
   }
6349
}
6350
#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