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

nickg / nvc / 12968353483

25 Jan 2025 08:55PM UTC coverage: 92.183% (-0.001%) from 92.184%
12968353483

push

github

nickg
Only compact objects when writing to disk

115 of 122 new or added lines in 13 files covered. (94.26%)

611 existing lines in 11 files now uncovered.

64154 of 69594 relevant lines covered (92.18%)

523959.05 hits per line

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

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

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

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

35
DECLARE_AND_DEFINE_ARRAY(vcode_reg);
8,447,311✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
394,744✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
261,832✔
38

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

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

106
DECLARE_AND_DEFINE_ARRAY(op);
12,826,527✔
107

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

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

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

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

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

159
DECLARE_AND_DEFINE_ARRAY(param);
31,676✔
160
DECLARE_AND_DEFINE_ARRAY(var);
381,373✔
161
DECLARE_AND_DEFINE_ARRAY(reg);
8,044,138✔
162
DECLARE_AND_DEFINE_ARRAY(block);
139,025✔
163
DECLARE_AND_DEFINE_ARRAY(vtype);
73,191,427✔
164

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

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

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

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

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

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

213
#define VCODE_CHECK_UNIONS 0
214

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

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

224
   return result;
225
}
226

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

233
   return result;
234
}
235

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

242
   return result;
243
}
244

245
static vcode_reg_t vcode_add_reg(vcode_type_t type)
1,300,008✔
246
{
247
   assert(active_unit != NULL);
1,300,008✔
248

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

255
   return reg;
1,300,008✔
256
}
257

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

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

270
   VCODE_ASSERT(
1,642,985✔
271
      !vcode_block_finished(),
272
      "attempt to add to already finished block %d", active_block);
273

274
   block_t *block = vcode_block_data();
1,642,985✔
275

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

282
   return op;
1,642,985✔
283
}
284

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

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

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

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

304
static op_t *vcode_find_definition(vcode_reg_t reg)
1,195,651✔
305
{
306
   for (int i = active_block; i >= 0; i--) {
1,243,399✔
307
      block_t *b = &(active_unit->blocks.items[i]);
1,240,481✔
308
      for (int j = b->ops.count - 1; j >= 0; j--) {
16,124,248✔
309
         if (b->ops.items[j].result == reg)
16,076,500✔
310
            return &(b->ops.items[j]);
1,192,733✔
311
      }
312
   }
313

314
   return NULL;
315
}
316

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

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

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

347
   int depth = MASK_CONTEXT(type);
70,650,563✔
348
   assert(depth <= unit->depth);
70,650,563✔
349
   while (depth != unit->depth)
72,316,590✔
350
      unit = unit->context;
1,666,027✔
351

352
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
70,650,563✔
353
}
354

355
static var_t *vcode_var_data(vcode_var_t var)
331,956✔
356
{
357
   assert(active_unit != NULL);
331,956✔
358
   assert(var != VCODE_INVALID_VAR);
331,956✔
359

360
   return var_array_nth_ptr(&(active_unit->vars), var);
331,956✔
361
}
362

363
void vcode_heap_allocate(vcode_reg_t reg)
19,783✔
364
{
365
   op_t *defn = vcode_find_definition(reg);
28,504✔
366
   if (defn == NULL) {
28,504✔
367
      // It is always safe to return a pointer to an argument
368
      return;
369
   }
370

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

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

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

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

403
         vcode_state_t state;
790✔
404
         vcode_state_save(&state);
790✔
405

406
         vcode_select_unit(vu);
790✔
407

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

411
         vcode_state_restore(&state);
790✔
412
      }
413
      break;
790✔
414

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

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

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

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

434
         // Any store to this variable must be heap allocated
435
         for (int i = 0; i < active_unit->blocks.count; i++) {
21,517✔
436
            block_t *b = &(active_unit->blocks.items[i]);
19,907✔
437
            for (int j = 0; j < b->ops.count; j++) {
275,787✔
438
               op_t *op = &(b->ops.items[j]);
255,880✔
439
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
255,880✔
440
                  vcode_heap_allocate(op->args.items[0]);
1,610✔
441

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

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

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

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

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

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

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

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

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

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

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

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

540
   if (unit == active_unit)
44,640✔
541
      vcode_close();
12,188✔
542

543
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
57,883✔
544
      assert(it->context == unit);
13,243✔
545
      it->context = NULL;
13,243✔
546
   }
547
   unit->children = NULL;
44,640✔
548

549
   if (unit->context != NULL) {
44,640✔
550
      vcode_unit_t *it = &(unit->context->children);
14,662✔
551
      for (; *it != NULL && *it != unit; it = &((*it)->next))
260,504✔
552
         ;
553
      assert(*it != NULL);
14,662✔
554
      *it = (*it)->next;
14,662✔
555
   }
556

557
   for (unsigned i = 0; i < unit->blocks.count; i++) {
183,643✔
558
      block_t *b = &(unit->blocks.items[i]);
139,003✔
559

560
      for (unsigned j = 0; j < b->ops.count; j++) {
1,706,725✔
561
         op_t *o = &(b->ops.items[j]);
1,567,722✔
562
         if (OP_HAS_COMMENT(o->kind))
1,567,722✔
563
            free(o->comment);
115,685✔
564
         if (OP_HAS_TARGET(o->kind))
1,567,722✔
565
            free(o->targets.items);
84,953✔
566
         free(o->args.items);
1,567,722✔
567
      }
568
      free(b->ops.items);
139,003✔
569
   }
570
   free(unit->blocks.items);
44,640✔
571

572
   for (unsigned i = 0; i < unit->types.count; i++) {
580,852✔
573
      vtype_t *vt = &(unit->types.items[i]);
536,212✔
574
      if (vt->kind == VCODE_TYPE_RECORD)
536,212✔
575
         free(vt->fields.items);
5,655✔
576
   }
577
   free(unit->types.items);
44,640✔
578

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

585
vcode_unit_t vcode_unit_next(vcode_unit_t unit)
25,165✔
586
{
587
   return unit->next;
25,165✔
588
}
589

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

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

601
vcode_type_t vcode_reg_type(vcode_reg_t reg)
4,647,820✔
602
{
603
   return vcode_reg_data(reg)->type;
4,647,820✔
604
}
605

606
vtype_kind_t vcode_reg_kind(vcode_reg_t reg)
1,156,734✔
607
{
608
   return vtype_kind(vcode_reg_type(reg));
1,156,734✔
609
}
610

611
vcode_type_t vcode_reg_bounds(vcode_reg_t reg)
221,553✔
612
{
613
   return vcode_reg_data(reg)->bounds;
221,553✔
614
}
615

616
bool vcode_reg_const(vcode_reg_t reg, int64_t *value)
697,978✔
617
{
618
   reg_t *r = vcode_reg_data(reg);
697,978✔
619

620
   vtype_kind_t kind = vtype_kind(r->type);
697,978✔
621
   if (kind != VCODE_TYPE_INT && kind != VCODE_TYPE_OFFSET)
697,978✔
622
      return false;
623

624
   vtype_t *bounds = vcode_type_data(r->bounds);
680,554✔
625

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

630
   if (bounds->low == bounds->high) {
680,554✔
631
      if (value) *value = bounds->low;
358,700✔
632
      return true;
358,700✔
633
   }
634
   else
635
      return false;
636
}
637

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

642
   int *uses LOCAL = xmalloc_array(active_unit->regs.count, sizeof(int));
89,300✔
643

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

649
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
287,049✔
650
         block_t *b = &(active_unit->blocks.items[i]);
226,300✔
651

652
         for (int j = b->ops.count - 1; j >= 0; j--) {
3,093,503✔
653
            op_t *o = &(b->ops.items[j]);
2,867,203✔
654

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

717
            default:
718
               break;
719
            }
720

721
            for (int k = 0; k < o->args.count; k++) {
7,767,717✔
722
               if (o->args.items[k] != VCODE_INVALID_REG)
4,900,514✔
723
                  uses[o->args.items[k]]++;
4,853,835✔
724
            }
725
         }
726
      }
727
   } while (pruned > 0);
60,749✔
728

729
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
183,675✔
730
      block_t *b = &(active_unit->blocks.items[i]);
139,025✔
731
      op_t *dst = &(b->ops.items[0]);
139,025✔
732
      size_t copied = 0;
139,025✔
733
      for (int j = 0; j < b->ops.count; j++) {
1,782,010✔
734
         const op_t *src = &(b->ops.items[j]);
1,642,985✔
735
         if (src->kind != (vcode_op_t)-1) {
1,642,985✔
736
            if (src != dst) {
1,568,091✔
737
               assert(dst < src);
418,790✔
738
               *dst = *src;
418,790✔
739
            }
740
            dst++;
1,568,091✔
741
            copied++;
1,568,091✔
742
         }
743
      }
744

745
      assert(copied <= b->ops.count);
139,025✔
746
      b->ops.count = copied;
139,025✔
747
   }
748
}
44,650✔
749

750
void vcode_close(void)
31,078✔
751
{
752
   active_unit  = NULL;
31,078✔
753
   active_block = -1;
31,078✔
754
}
31,078✔
755

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

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

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

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

783
   return VCODE_INVALID_VAR;
784
}
785

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

791
vcode_type_t vcode_var_type(vcode_var_t var)
142,332✔
792
{
793
   return vcode_var_data(var)->type;
142,332✔
794
}
795

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

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

806
vcode_op_t vcode_get_op(int op)
4,510,775✔
807
{
808
   return vcode_op_data(op)->kind;
4,510,775✔
809
}
810

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

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

825
object_t *vcode_get_object(int op)
65,403✔
826
{
827
   op_t *o = vcode_op_data(op);
65,403✔
828
   assert(OP_HAS_IDENT(o->kind));
65,403✔
829
   return o->object;
65,403✔
830
}
831

832
int64_t vcode_get_value(int op)
316,586✔
833
{
834
   op_t *o = vcode_op_data(op);
316,586✔
835
   assert(OP_HAS_VALUE(o->kind));
316,586✔
836
   return o->value;
316,586✔
837
}
838

839
double vcode_get_real(int op)
20,755✔
840
{
841
   op_t *o = vcode_op_data(op);
20,755✔
842
   assert(OP_HAS_REAL(o->kind));
20,755✔
843
   return o->real;
20,755✔
844
}
845

846
vcode_var_t vcode_get_address(int op)
149,700✔
847
{
848
   op_t *o = vcode_op_data(op);
149,700✔
849
   assert(OP_HAS_ADDRESS(o->kind));
149,700✔
850
   return o->address;
149,700✔
851
}
852

853
unsigned vcode_get_dim(int op)
69,676✔
854
{
855
   op_t *o = vcode_op_data(op);
69,676✔
856
   assert(OP_HAS_DIM(o->kind));
69,676✔
857
   return o->dim;
69,676✔
858
}
859

860
int vcode_get_hops(int op)
62,596✔
861
{
862
   op_t *o = vcode_op_data(op);
62,596✔
863
   assert(OP_HAS_HOPS(o->kind));
62,596✔
864
   return o->hops;
62,596✔
865
}
866

867
int vcode_get_field(int op)
37,189✔
868
{
869
   op_t *o = vcode_op_data(op);
37,189✔
870
   assert(OP_HAS_FIELD(o->kind));
37,189✔
871
   return o->field;
37,189✔
872
}
873

874
vcode_var_t vcode_get_type(int op)
18,151✔
875
{
876
   op_t *o = vcode_op_data(op);
18,151✔
877
   assert(OP_HAS_TYPE(o->kind));
18,151✔
878
   return o->type;
18,151✔
879
}
880

881
int vcode_count_args(int op)
196,945✔
882
{
883
   return vcode_op_data(op)->args.count;
196,945✔
884
}
885

886
vcode_reg_t vcode_get_arg(int op, int arg)
2,821,481✔
887
{
888
   op_t *o = vcode_op_data(op);
2,821,481✔
889
   return vcode_reg_array_nth(&(o->args), arg);
2,821,481✔
890
}
891

892
vcode_reg_t vcode_get_result(int op)
1,141,231✔
893
{
894
   op_t *o = vcode_op_data(op);
1,141,231✔
895
   return o->result;
1,141,231✔
896
}
897

898
vcode_cmp_t vcode_get_cmp(int op)
33,511✔
899
{
900
   op_t *o = vcode_op_data(op);
33,511✔
901
   assert(OP_HAS_CMP(o->kind));
33,511✔
902
   return o->cmp;
33,511✔
903
}
904

905
uint32_t vcode_get_tag(int op)
2,638✔
906
{
907
   op_t *o = vcode_op_data(op);
2,638✔
908
   assert(OP_HAS_TAG(o->kind));
2,638✔
909
   return o->tag;
2,638✔
910
}
911

912
const loc_t *vcode_get_loc(int op)
1,456,221✔
913
{
914
   op_t *o = vcode_op_data(op);
1,456,221✔
915
   return &(o->loc);
1,456,221✔
916
}
917

918
vcode_block_t vcode_get_target(int op, int nth)
147,432✔
919
{
920
   op_t *o = vcode_op_data(op);
147,432✔
921
   assert(OP_HAS_TARGET(o->kind));
147,432✔
922
   return vcode_block_array_nth(&(o->targets), nth);
147,432✔
923
}
924

UNCOV
925
bool vcode_block_empty(void)
×
926
{
UNCOV
927
   assert(active_unit != NULL);
×
UNCOV
928
   assert(active_block != VCODE_INVALID_BLOCK);
×
929

UNCOV
930
   return active_unit->blocks.items[active_block].ops.count == 0;
×
931
}
932

933
bool vcode_block_finished(void)
1,747,756✔
934
{
935
   assert(active_unit != NULL);
1,747,756✔
936
   assert(active_block != VCODE_INVALID_BLOCK);
1,747,756✔
937

938
   const block_t *b = &(active_unit->blocks.items[active_block]);
1,747,756✔
939
   if (b->ops.count == 0)
1,747,756✔
940
      return false;
941
   else {
942
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,564,823✔
943
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,564,823✔
944
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,564,799✔
945
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
946
         || kind == VCODE_OP_UNREACHABLE;
3,129,622✔
947
   }
948
}
949

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

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

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

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

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

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

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

1059
   case VCODE_TYPE_POINTER:
1060
      col += printf("@<");
1061
      col += vcode_dump_one_type(vt->pointed);
1062
      col += printf(">");
1063
      break;
1064

1065
   case VCODE_TYPE_ACCESS:
1066
      col += printf("A<");
1067
      col += vcode_dump_one_type(vt->pointed);
1068
      col += printf(">");
1069
      break;
1070

1071
   case VCODE_TYPE_SIGNAL:
1072
      col += printf("$<");
1073
      col += vcode_dump_one_type(vt->base);
1074
      col += printf(">");
1075
      break;
1076

1077
   case VCODE_TYPE_OFFSET:
1078
      col += printf("#");
1079
      break;
1080

1081
   case VCODE_TYPE_RECORD:
1082
      col += printf("%s{}", istr(vt->name));
1083
      break;
1084

1085
   case VCODE_TYPE_FILE:
1086
      col += printf("F<");
1087
      col += vcode_dump_one_type(vt->base);
1088
      col += printf(">");
1089
      break;
1090

1091
   case VCODE_TYPE_OPAQUE:
1092
      col += printf("?");
1093
      break;
1094

1095
   case VCODE_TYPE_RESOLUTION:
1096
      col += printf("R<");
1097
      col += vcode_dump_one_type(vt->base);
1098
      col += printf(">");
1099
      break;
1100

1101
   case VCODE_TYPE_CLOSURE:
1102
      col += printf("C<");
1103
      col += vcode_dump_one_type(vt->base);
1104
      col += printf(">");
1105
      break;
1106

1107
   case VCODE_TYPE_CONTEXT:
1108
      col += printf("P<%s>", istr(vt->name));
1109
      break;
1110

1111
   case VCODE_TYPE_DEBUG_LOCUS:
1112
      col += printf("D<>");
1113
      break;
1114

1115
   case VCODE_TYPE_TRIGGER:
1116
      col += printf("T<>");
1117
      break;
1118

1119
   case VCODE_TYPE_CONVERSION:
1120
      col += printf("X<>");
1121
      break;
1122
   }
1123

1124
   return col;
1125
}
1126

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

1137
static void vcode_dump_comment(int col)
1138
{
1139
   vcode_dump_tab(col, 40);
1140
   color_printf("$cyan$// ");
1141
}
1142

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

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

1161
static int vcode_dump_var(vcode_var_t var, int hops)
1162
{
1163
   vcode_unit_t owner = active_unit;
1164
   while (owner && hops--)
1165
      owner = owner->context;
1166

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

1175
void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg)
1176
{
1177
   assert(active_unit != NULL);
1178

1179
   const vcode_unit_t vu = active_unit;
1180
   vcode_block_t old_block = active_block;
1181

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

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

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

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

1238
   if (vu->result != VCODE_INVALID_TYPE) {
1239
      color_printf("Result     $cyan$");
1240
      vcode_dump_one_type(vu->result);
1241
      color_printf("$$\n");
1242
   }
1243

1244
   if (vu->kind == VCODE_UNIT_FUNCTION
1245
       || vu->kind == VCODE_UNIT_PROCEDURE
1246
       || vu->kind == VCODE_UNIT_PROPERTY
1247
       || (vu->kind == VCODE_UNIT_PROTECTED && vu->params.count > 0)) {
1248

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1416
         case VCODE_OP_POP_SCOPE:
1417
            {
1418
               printf("%s", vcode_op_string(op->kind));
1419
            }
1420
            break;
1421

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

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

1460
         case VCODE_OP_RESOLUTION_WRAPPER:
1461
            {
1462
               col += vcode_dump_reg(op->result);
1463
               col += color_printf(" := %s ", vcode_op_string(op->kind));
1464
               col += vcode_dump_reg(op->args.items[0]);
1465
               col += printf(" ileft ");
1466
               col += vcode_dump_reg(op->args.items[1]);
1467
               col += printf(" nlits ");
1468
               col += vcode_dump_reg(op->args.items[2]);
1469
               vcode_dump_result_type(col, op);
1470
            }
1471
            break;
1472

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

1490
         case VCODE_OP_PACKAGE_INIT:
1491
            {
1492
               col += vcode_dump_reg(op->result);
1493
               col += color_printf(" := %s $magenta$%s$$",
1494
                                   vcode_op_string(op->kind), istr(op->func));
1495
               if (op->args.count > 0) {
1496
                  col += printf(" context " );
1497
                  col += vcode_dump_reg(op->args.items[0]);
1498
               }
1499
               vcode_dump_result_type(col, op);
1500
            }
1501
            break;
1502

1503
         case VCODE_OP_PROCESS_INIT:
1504
            {
1505
               color_printf("%s $magenta$%s$$ locus ",
1506
                            vcode_op_string(op->kind), istr(op->func));
1507
               vcode_dump_reg(op->args.items[0]);
1508
            }
1509
            break;
1510

1511
         case VCODE_OP_PROTECTED_FREE:
1512
            {
1513
               printf("%s ", vcode_op_string(op->kind));
1514
               vcode_dump_reg(op->args.items[0]);
1515
            }
1516
            break;
1517

1518
         case VCODE_OP_WAIT:
1519
            {
1520
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1521
                            op->targets.items[0]);
1522
               if (op->args.items[0] != VCODE_INVALID_REG) {
1523
                  printf(" for ");
1524
                  vcode_dump_reg(op->args.items[0]);
1525
               }
1526
            }
1527
            break;
1528

1529
         case VCODE_OP_JUMP:
1530
            {
1531
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1532
                            op->targets.items[0]);
1533
            }
1534
            break;
1535

1536
         case VCODE_OP_COND:
1537
            {
1538
               printf("%s ", vcode_op_string(op->kind));
1539
               vcode_dump_reg(op->args.items[0]);
1540
               color_printf(" then $yellow$%d$$ else $yellow$%d$$",
1541
                            op->targets.items[0], op->targets.items[1]);
1542
            }
1543
            break;
1544

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

1568
         case VCODE_OP_REPORT:
1569
            {
1570
               printf("%s ", vcode_op_string(op->kind));
1571
               vcode_dump_reg(op->args.items[1]);
1572
               printf(" length ");
1573
               vcode_dump_reg(op->args.items[2]);
1574
               printf(" severity ");
1575
               vcode_dump_reg(op->args.items[0]);
1576
               printf(" locus ");
1577
               vcode_dump_reg(op->args.items[3]);
1578
            }
1579
            break;
1580

1581
         case VCODE_OP_LOAD:
1582
            {
1583
               col += vcode_dump_reg(op->result);
1584
               col += printf(" := %s ", vcode_op_string(op->kind));
1585
               col += vcode_dump_var(op->address, 0);
1586
               vcode_dump_result_type(col, op);
1587
            }
1588
            break;
1589

1590
         case VCODE_OP_LOAD_INDIRECT:
1591
            {
1592
               col += vcode_dump_reg(op->result);
1593
               col += color_printf(" := %s ", vcode_op_string(op->kind));
1594
               col += vcode_dump_reg(op->args.items[0]);
1595
               vcode_dump_result_type(col, op);
1596
            }
1597
            break;
1598

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

1607
         case VCODE_OP_STORE_INDIRECT:
1608
            {
1609
               vcode_dump_reg(op->args.items[1]);
1610
               printf(" := %s ", vcode_op_string(op->kind));
1611
               vcode_dump_reg(op->args.items[0]);
1612
            }
1613
            break;
1614

1615
         case VCODE_OP_INDEX:
1616
            {
1617
               col += vcode_dump_reg(op->result);
1618
               col += printf(" := %s ", vcode_op_string(op->kind));
1619
               col += vcode_dump_var(op->address, 0);
1620
               if (op->args.count > 0) {
1621
                  col += printf(" + ");
1622
                  col += vcode_dump_reg(op->args.items[0]);
1623
               }
1624
               vcode_dump_result_type(col, op);
1625
            }
1626
            break;
1627

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

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

1688
         case VCODE_OP_NOT:
1689
            {
1690
               col += vcode_dump_reg(op->result);
1691
               col += printf(" := %s ", vcode_op_string(op->kind));
1692
               col += vcode_dump_reg(op->args.items[0]);
1693
               vcode_dump_result_type(col, op);
1694
            }
1695
            break;
1696

1697
         case VCODE_OP_COMMENT:
1698
            {
1699
               color_printf("$cyan$// %s$$ ", op->comment);
1700
            }
1701
            break;
1702

1703
         case VCODE_OP_CONST_ARRAY:
1704
         case VCODE_OP_CONST_RECORD:
1705
            {
1706
               col += vcode_dump_reg(op->result);
1707
               col += printf(" := const %c",
1708
                             op->kind == VCODE_OP_CONST_ARRAY ? '[' : '{');
1709
               for (int k = 0; k < op->args.count; k++) {
1710
                  if (k > 0)
1711
                     col += printf(",");
1712
                  col += vcode_dump_reg(op->args.items[k]);
1713
               }
1714

1715
               putchar(op->kind == VCODE_OP_CONST_ARRAY ? ']' : '}');
1716
               vcode_dump_result_type(col + 1, op);
1717
            }
1718
            break;
1719

1720
         case VCODE_OP_CONST_REP:
1721
            {
1722
               col += vcode_dump_reg(op->result);
1723
               col += printf(" := const [");
1724
               col += vcode_dump_reg(op->args.items[0]);
1725
               col += printf("]*%"PRIi64, op->value);
1726
               vcode_dump_result_type(col, op);
1727
            }
1728
            break;
1729

1730
         case VCODE_OP_ADDRESS_OF:
1731
         case VCODE_OP_CAST:
1732
            {
1733
               col += vcode_dump_reg(op->result);
1734
               col += printf(" := %s ", vcode_op_string(op->kind));
1735
               col += vcode_dump_reg(op->args.items[0]);
1736
               vcode_dump_result_type(col, op);
1737
            }
1738
            break;
1739

1740
         case VCODE_OP_RETURN:
1741
            {
1742
               printf("%s ", vcode_op_string(op->kind));
1743
               if (op->args.count > 0)
1744
                  vcode_dump_reg(op->args.items[0]);
1745
            }
1746
            break;
1747

1748
         case VCODE_OP_SCHED_WAVEFORM:
1749
            {
1750
               printf("%s ", vcode_op_string(op->kind));
1751
               vcode_dump_reg(op->args.items[0]);
1752
               printf(" count ");
1753
               vcode_dump_reg(op->args.items[1]);
1754
               printf(" values ");
1755
               vcode_dump_reg(op->args.items[2]);
1756
               printf(" reject ");
1757
               vcode_dump_reg(op->args.items[3]);
1758
               printf(" after ");
1759
               vcode_dump_reg(op->args.items[4]);
1760
            }
1761
            break;
1762

1763
         case VCODE_OP_FORCE:
1764
         case VCODE_OP_RELEASE:
1765
         case VCODE_OP_DEPOSIT_SIGNAL:
1766
            {
1767
               printf("%s ", vcode_op_string(op->kind));
1768
               vcode_dump_reg(op->args.items[0]);
1769
               printf(" count ");
1770
               vcode_dump_reg(op->args.items[1]);
1771
               if (op->args.count > 2) {
1772
                  printf(" values ");
1773
                  vcode_dump_reg(op->args.items[2]);
1774
               }
1775
            }
1776
            break;
1777

1778
         case VCODE_OP_DISCONNECT:
1779
            {
1780
               printf("%s ", vcode_op_string(op->kind));
1781
               vcode_dump_reg(op->args.items[0]);
1782
               printf(" count ");
1783
               vcode_dump_reg(op->args.items[1]);
1784
               printf(" reject ");
1785
               vcode_dump_reg(op->args.items[2]);
1786
               printf(" after ");
1787
               vcode_dump_reg(op->args.items[3]);
1788
            }
1789
            break;
1790

1791
         case VCODE_OP_NEG:
1792
         case VCODE_OP_TRAP_NEG:
1793
         case VCODE_OP_ABS:
1794
         case VCODE_OP_RESOLVED:
1795
         case VCODE_OP_LAST_VALUE:
1796
            {
1797
               col += vcode_dump_reg(op->result);
1798
               col += printf(" := %s ", vcode_op_string(op->kind));
1799
               col += vcode_dump_reg(op->args.items[0]);
1800
               if (op->args.count > 1) {
1801
                  col += printf(" locus ");
1802
                  col += vcode_dump_reg(op->args.items[1]);
1803
               }
1804
               vcode_dump_result_type(col, op);
1805
            }
1806
            break;
1807

1808
         case VCODE_OP_SELECT:
1809
            {
1810
               col += vcode_dump_reg(op->result);
1811
               col += printf(" := %s ", vcode_op_string(op->kind));
1812
               col += vcode_dump_reg(op->args.items[0]);
1813
               col += printf(" then ");
1814
               col += vcode_dump_reg(op->args.items[1]);
1815
               col += printf(" else ");
1816
               col += vcode_dump_reg(op->args.items[2]);
1817
               vcode_dump_result_type(col, op);
1818
            }
1819
            break;
1820

1821
         case VCODE_OP_WRAP:
1822
            {
1823
               col += vcode_dump_reg(op->result);
1824
               col += printf(" := %s ", vcode_op_string(op->kind));
1825
               col += vcode_dump_reg(op->args.items[0]);
1826
               col += printf(" [");
1827
               for (int i = 1; i < op->args.count; i += 3) {
1828
                  if (i > 1)
1829
                     col += printf(", ");
1830
                  col += vcode_dump_reg(op->args.items[i + 0]);
1831
                  col += printf(" ");
1832
                  col += vcode_dump_reg(op->args.items[i + 1]);
1833
                  col += printf(" ");
1834
                  col += vcode_dump_reg(op->args.items[i + 2]);
1835
               }
1836
               col += printf("]");
1837
               vcode_dump_result_type(col, op);
1838
            }
1839
            break;
1840

1841
         case VCODE_OP_UARRAY_LEFT:
1842
         case VCODE_OP_UARRAY_RIGHT:
1843
         case VCODE_OP_UARRAY_DIR:
1844
         case VCODE_OP_UARRAY_LEN:
1845
            {
1846
               col += vcode_dump_reg(op->result);
1847
               col += printf(" := %s ", vcode_op_string(op->kind));
1848
               col += vcode_dump_reg(op->args.items[0]);
1849
               col += printf(" dim %d", op->dim);
1850
               vcode_dump_result_type(col, op);
1851
            }
1852
            break;
1853

1854
         case VCODE_OP_UNWRAP:
1855
            {
1856
               col += vcode_dump_reg(op->result);
1857
               col += printf(" := %s ", vcode_op_string(op->kind));
1858
               col += vcode_dump_reg(op->args.items[0]);
1859
               vcode_dump_result_type(col, op);
1860
            }
1861
            break;
1862

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

1873
         case VCODE_OP_CONTEXT_UPREF:
1874
            {
1875
               col += vcode_dump_reg(op->result);
1876
               col += printf(" := %s %d", vcode_op_string(op->kind), op->hops);
1877
               vcode_dump_result_type(col, op);
1878
            }
1879
            break;
1880

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

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

1904
         case VCODE_OP_ARRAY_REF:
1905
            {
1906
               col += vcode_dump_reg(op->result);
1907
               col += printf(" := %s ", vcode_op_string(op->kind));
1908
               col += vcode_dump_reg(op->args.items[0]);
1909
               col += printf(" offset ");
1910
               col += vcode_dump_reg(op->args.items[1]);
1911
               vcode_dump_result_type(col, op);
1912
            }
1913
            break;
1914

1915
         case VCODE_OP_COPY:
1916
            {
1917
               vcode_dump_reg(op->args.items[0]);
1918
               printf(" := %s ", vcode_op_string(op->kind));
1919
               vcode_dump_reg(op->args.items[1]);
1920
               if (op->args.count > 2) {
1921
                  printf(" count " );
1922
                  vcode_dump_reg(op->args.items[2]);
1923
               }
1924
            }
1925
            break;
1926

1927
         case VCODE_OP_SCHED_EVENT:
1928
         case VCODE_OP_CLEAR_EVENT:
1929
            {
1930
               printf("%s on ", vcode_op_string(op->kind));
1931
               vcode_dump_reg(op->args.items[0]);
1932
               printf(" count ");
1933
               vcode_dump_reg(op->args.items[1]);
1934
            }
1935
            break;
1936

1937
         case VCODE_OP_PCALL:
1938
            {
1939
               color_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
1940
                            istr(op->func));
1941
               for (int i = 0; i < op->args.count; i++) {
1942
                  printf("%s", i > 0 ? ", " : " ");
1943
                  vcode_dump_reg(op->args.items[i]);
1944
               }
1945
               if (op->targets.count > 0)
1946
                  color_printf(" resume $yellow$%d$$", op->targets.items[0]);
1947
            }
1948
            break;
1949

1950
         case VCODE_OP_RESUME:
1951
            {
1952
               color_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
1953
                            istr(op->func));
1954
            }
1955
            break;
1956

1957
         case VCODE_OP_MEMSET:
1958
            {
1959
               vcode_dump_reg(op->args.items[0]);
1960
               printf(" := %s ", vcode_op_string(op->kind));
1961
               vcode_dump_reg(op->args.items[1]);
1962
               printf(" length ");
1963
               vcode_dump_reg(op->args.items[2]);
1964
            }
1965
            break;
1966

1967
         case VCODE_OP_CASE:
1968
            {
1969
               printf("%s ", vcode_op_string(op->kind));
1970
               vcode_dump_reg(op->args.items[0]);
1971
               color_printf(" default $yellow$%d$$", op->targets.items[0]);
1972
               for (int i = 1; i < op->args.count; i++) {
1973
                  printf(" [");
1974
                  vcode_dump_reg(op->args.items[i]);
1975
                  color_printf(" $yellow$%d$$]", op->targets.items[i]);
1976
               }
1977
            }
1978
            break;
1979

1980
         case VCODE_OP_FILE_OPEN:
1981
            {
1982
               printf("%s ", vcode_op_string(op->kind));
1983
               vcode_dump_reg(op->args.items[0]);
1984
               printf(" name ");
1985
               vcode_dump_reg(op->args.items[1]);
1986
               printf(" length ");
1987
               vcode_dump_reg(op->args.items[2]);
1988
               printf(" kind ");
1989
               vcode_dump_reg(op->args.items[3]);
1990
               if (op->args.count == 5) {
1991
                  printf(" status ");
1992
                  vcode_dump_reg(op->args.items[4]);
1993
               }
1994
            }
1995
            break;
1996

1997
         case VCODE_OP_FILE_WRITE:
1998
            {
1999
               printf("%s ", vcode_op_string(op->kind));
2000
               vcode_dump_reg(op->args.items[0]);
2001
               printf(" value ");
2002
               vcode_dump_reg(op->args.items[1]);
2003
               if (op->args.count == 3) {
2004
                  printf(" length ");
2005
                  vcode_dump_reg(op->args.items[2]);
2006
               }
2007
            }
2008
            break;
2009

2010
         case VCODE_OP_FILE_READ:
2011
            {
2012
               printf("%s ", vcode_op_string(op->kind));
2013
               vcode_dump_reg(op->args.items[0]);
2014
               printf(" ptr ");
2015
               vcode_dump_reg(op->args.items[1]);
2016
               if (op->args.count >= 3) {
2017
                  printf(" inlen ");
2018
                  vcode_dump_reg(op->args.items[2]);
2019
                  if (op->args.count >= 4) {
2020
                     printf(" outlen ");
2021
                     vcode_dump_reg(op->args.items[3]);
2022
                  }
2023
               }
2024
            }
2025
            break;
2026

2027
         case VCODE_OP_NULL:
2028
         case VCODE_OP_NEW:
2029
            {
2030
               col += vcode_dump_reg(op->result);
2031
               col += printf(" := %s", vcode_op_string(op->kind));
2032
               if (op->args.count == 1) {
2033
                  col += printf(" length ");
2034
                  col += vcode_dump_reg(op->args.items[0]);
2035
               }
2036
               vcode_dump_result_type(col, op);
2037
            }
2038
            break;
2039

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

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

2056
         case VCODE_OP_ALL:
2057
            {
2058
               col += vcode_dump_reg(op->result);
2059
               col += printf(" := %s ", vcode_op_string(op->kind));
2060
               col += vcode_dump_reg(op->args.items[0]);
2061
               vcode_dump_result_type(col, op);
2062
            }
2063
            break;
2064

2065
         case VCODE_OP_LAST_EVENT:
2066
         case VCODE_OP_LAST_ACTIVE:
2067
         case VCODE_OP_DRIVING_VALUE:
2068
            {
2069
               col += vcode_dump_reg(op->result);
2070
               col += printf(" := %s ", vcode_op_string(op->kind));
2071
               col += vcode_dump_reg(op->args.items[0]);
2072
               if (op->args.count > 1) {
2073
                  col += printf(" length ");
2074
                  col += vcode_dump_reg(op->args.items[1]);
2075
               }
2076
               vcode_dump_result_type(col, op);
2077
            }
2078
            break;
2079

2080
         case VCODE_OP_ALIAS_SIGNAL:
2081
            {
2082
               printf("%s ", vcode_op_string(op->kind));
2083
               vcode_dump_reg(op->args.items[0]);
2084
               printf(" locus ");
2085
               vcode_dump_reg(op->args.items[1]);
2086
            }
2087
            break;
2088

2089
         case VCODE_OP_LENGTH_CHECK:
2090
            {
2091
               col += printf("%s left ", vcode_op_string(op->kind));
2092
               col += vcode_dump_reg(op->args.items[0]);
2093
               col += printf(" == right ");
2094
               col += vcode_dump_reg(op->args.items[1]);
2095
               col += printf(" locus ");
2096
               col += vcode_dump_reg(op->args.items[2]);
2097
               if (op->args.count > 3) {
2098
                  col += printf(" dim ");
2099
                  col += vcode_dump_reg(op->args.items[3]);
2100
               }
2101
            }
2102
            break;
2103

2104
         case VCODE_OP_EXPONENT_CHECK:
2105
         case VCODE_OP_ZERO_CHECK:
2106
            {
2107
               col += printf("%s ", vcode_op_string(op->kind));
2108
               col += vcode_dump_reg(op->args.items[0]);
2109
               col += printf(" locus ");
2110
               col += vcode_dump_reg(op->args.items[1]);
2111
            }
2112
            break;
2113

2114
         case VCODE_OP_INDEX_CHECK:
2115
         case VCODE_OP_RANGE_CHECK:
2116
            {
2117
               col += printf("%s ", vcode_op_string(op->kind));
2118
               col += vcode_dump_reg(op->args.items[0]);
2119
               col += printf(" left ");
2120
               col += vcode_dump_reg(op->args.items[1]);
2121
               col += printf(" right ");
2122
               col += vcode_dump_reg(op->args.items[2]);
2123
               col += printf(" dir ");
2124
               col += vcode_dump_reg(op->args.items[3]);
2125
               col += printf(" locus ");
2126
               col += vcode_dump_reg(op->args.items[4]);
2127
               if (op->args.items[5] != op->args.items[4]) {
2128
                  col += printf(" hint ");
2129
                  col += vcode_dump_reg(op->args.items[5]);
2130
               }
2131
            }
2132
            break;
2133

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

2141
         case VCODE_OP_COVER_STMT:
2142
         case VCODE_OP_COVER_BRANCH:
2143
         case VCODE_OP_COVER_EXPR:
2144
            {
2145
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2146
            }
2147
            break;
2148

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

2157
         case VCODE_OP_UNDEFINED:
2158
            {
2159
               col += vcode_dump_reg(op->result);
2160
               col += printf(" := %s", vcode_op_string(op->kind));
2161
               vcode_dump_result_type(col, op);
2162
            }
2163
            break;
2164

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

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

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

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

2212
         case VCODE_OP_DEBUG_LOCUS:
2213
            {
2214
               col += vcode_dump_reg(op->result);
2215
               col += color_printf(" := %s $magenta$",
2216
                                   vcode_op_string(op->kind));
2217

2218
               tree_t t = tree_from_object(op->object);
2219
               if (t != NULL)
2220
                  col += printf("%s@", tree_kind_str(tree_kind(t)));
2221

2222
               col += color_printf("%p$$", op->object);
2223
               vcode_dump_result_type(col, op);
2224
            }
2225
            break;
2226

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

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

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

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

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

2298
         case VCODE_OP_ADD_TRIGGER:
2299
            {
2300
               printf("%s ", vcode_op_string(op->kind));
2301
               vcode_dump_reg(op->args.items[0]);
2302
            }
2303
            break;
2304

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

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

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

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

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

2368
         if (j == mark_op && i == old_block)
2369
            color_printf("\t $red$<----$$");
2370

2371
         color_printf("$$\n");
2372

2373
         if (callback != NULL)
2374
            (*callback)(j, arg);
2375
      }
2376

2377
      if (b->ops.count == 0)
2378
         color_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2379
   }
2380

2381
   printf("\n");
2382
   fflush(stdout);
2383

2384
   active_block = old_block;
2385
}
2386
LCOV_EXCL_STOP
2387

2388
bool vtype_eq(vcode_type_t a, vcode_type_t b)
32,956,630✔
2389
{
2390
   assert(active_unit != NULL);
33,506,022✔
2391

2392
   if (a == b)
33,506,022✔
2393
      return true;
2394
   else {
2395
      const vtype_t *at = vcode_type_data(a);
30,878,711✔
2396
      const vtype_t *bt = vcode_type_data(b);
30,878,711✔
2397

2398
      if (at->kind != bt->kind)
30,878,711✔
2399
         return false;
2400

2401
      switch (at->kind) {
13,390,217✔
2402
      case VCODE_TYPE_INT:
11,298,470✔
2403
         return (at->low == bt->low) && (at->high == bt->high);
21,217,469✔
2404
      case VCODE_TYPE_REAL:
979,034✔
2405
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
1,906,342✔
2406
      case VCODE_TYPE_CARRAY:
73,585✔
2407
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
80,320✔
2408
      case VCODE_TYPE_UARRAY:
89,322✔
2409
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
111,167✔
2410
      case VCODE_TYPE_POINTER:
456,609✔
2411
      case VCODE_TYPE_ACCESS:
2412
         return vtype_eq(at->pointed, bt->pointed);
456,609✔
2413
      case VCODE_TYPE_OFFSET:
2414
      case VCODE_TYPE_OPAQUE:
2415
      case VCODE_TYPE_DEBUG_LOCUS:
2416
      case VCODE_TYPE_TRIGGER:
2417
      case VCODE_TYPE_CONVERSION:
2418
         return true;
2419
      case VCODE_TYPE_RESOLUTION:
92,783✔
2420
      case VCODE_TYPE_CLOSURE:
2421
      case VCODE_TYPE_SIGNAL:
2422
      case VCODE_TYPE_FILE:
2423
         return vtype_eq(at->base, bt->base);
92,783✔
2424
      case VCODE_TYPE_RECORD:
65,318✔
2425
      case VCODE_TYPE_CONTEXT:
2426
         return at->name == bt->name;
65,318✔
2427
      }
2428

UNCOV
2429
      return false;
×
2430
   }
2431
}
2432

UNCOV
2433
void vcode_dump(void)
×
2434
{
UNCOV
2435
   vcode_dump_with_mark(-1, NULL, NULL);
×
UNCOV
2436
}
×
2437

2438
static vcode_type_t vtype_new(vtype_t *new)
2,540,864✔
2439
{
2440
   int index = active_unit->types.count - 1;
2,540,864✔
2441
   vcode_type_t type = MAKE_HANDLE(active_unit->depth, index);
2,540,864✔
2442

2443
   for (int i = 0; i < index; i++) {
30,580,168✔
2444
      vcode_type_t this = MAKE_HANDLE(active_unit->depth, i);
30,043,762✔
2445
      if (vtype_eq(this, type)) {
30,043,762✔
2446
         active_unit->types.count--;
2,004,458✔
2447
         return this;
2,004,458✔
2448
      }
2449
   }
2450

2451
   return type;
2452
}
2453

2454
vcode_type_t vtype_int(int64_t low, int64_t high)
1,666,747✔
2455
{
2456
   assert(active_unit != NULL);
1,666,747✔
2457

2458
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,666,747✔
2459
   n->kind = VCODE_TYPE_INT;
1,666,747✔
2460
   n->low  = low;
1,666,747✔
2461
   n->high = high;
1,666,747✔
2462

2463
   switch (bits_for_range(low, high)) {
1,666,747✔
2464
   case 64:
128,861✔
2465
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
128,861✔
2466
      break;
128,861✔
2467
   case 32:
510,105✔
2468
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
510,105✔
2469
      break;
510,105✔
2470
   case 16:
3,537✔
2471
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
3,537✔
2472
      break;
3,537✔
2473
   case 8:
441,833✔
2474
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
441,833✔
2475
      break;
441,833✔
2476
   case 1:
582,410✔
2477
      n->repr = VCODE_REPR_U1;
582,410✔
2478
      break;
582,410✔
2479
   case 0:
1✔
2480
      n->repr = VCODE_REPR_I64;    // Null range
1✔
2481
      break;
1✔
UNCOV
2482
   default:
×
2483
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2484
   }
2485

2486
   return vtype_new(n);
1,666,747✔
2487
}
2488

2489
vcode_type_t vtype_bool(void)
292,774✔
2490
{
2491
   return vtype_int(0, 1);
292,774✔
2492
}
2493

2494
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
36,989✔
2495
{
2496
   assert(active_unit != NULL);
36,989✔
2497

2498
   const vtype_kind_t ekind = vtype_kind(elem);
36,989✔
2499
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
36,989✔
2500
                "array types may not be nested");
2501

2502
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
36,989✔
2503
   memset(n, '\0', sizeof(vtype_t));
36,989✔
2504
   n->kind   = VCODE_TYPE_CARRAY;
36,989✔
2505
   n->elem   = elem;
36,989✔
2506
   n->bounds = bounds;
36,989✔
2507
   n->size   = MAX(size, 0);
36,989✔
2508

2509
   return vtype_new(n);
36,989✔
2510
}
2511

2512
vcode_type_t vtype_find_named_record(ident_t name)
37,630✔
2513
{
2514
   assert(active_unit != NULL);
37,630✔
2515

2516
   for (int i = 0; i < active_unit->types.count; i++) {
487,187✔
2517
      vtype_t *other = &(active_unit->types.items[i]);
475,896✔
2518
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
475,896✔
2519
         return MAKE_HANDLE(active_unit->depth, i);
26,339✔
2520
   }
2521

2522
   return VCODE_INVALID_TYPE;
2523
}
2524

2525
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
11,291✔
2526
                                int nfields)
2527
{
2528
   assert(active_unit != NULL);
11,291✔
2529

2530
   vtype_t *data = NULL;
11,291✔
2531
   vcode_type_t handle = vtype_find_named_record(name);
11,291✔
2532
   if (handle == VCODE_INVALID_TYPE) {
11,291✔
2533
      data = vtype_array_alloc(&(active_unit->types));
5,655✔
2534
      memset(data, '\0', sizeof(vtype_t));
5,655✔
2535
      data->kind = VCODE_TYPE_RECORD;
5,655✔
2536
      data->name = name;
5,655✔
2537

2538
      handle = vtype_new(data);
5,655✔
2539
   }
2540
   else {
2541
      data = vcode_type_data(handle);
5,636✔
2542
      VCODE_ASSERT(data->fields.count == 0,
5,636✔
2543
                    "record type %s already defined", istr(name));
2544
   }
2545

2546
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
11,291✔
2547
   for (int i = 0; i < nfields; i++)
30,259✔
2548
      vcode_type_array_add(&(data->fields), field_types[i]);
18,968✔
2549

2550
   return handle;
11,291✔
2551
}
2552

2553
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
84,309✔
2554
{
2555
   assert(active_unit != NULL);
84,309✔
2556

2557
   const vtype_kind_t ekind = vtype_kind(elem);
84,309✔
2558
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
84,309✔
2559
                "array types may not be nested");
2560

2561
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
84,309✔
2562

2563
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
84,309✔
2564
   memset(n, '\0', sizeof(vtype_t));
84,309✔
2565
   n->kind   = VCODE_TYPE_UARRAY;
84,309✔
2566
   n->elem   = elem;
84,309✔
2567
   n->bounds = bounds;
84,309✔
2568
   n->dims   = ndim;
84,309✔
2569

2570
   return vtype_new(n);
84,309✔
2571
}
2572

2573
vcode_type_t vtype_pointer(vcode_type_t to)
187,849✔
2574
{
2575
   assert(active_unit != NULL);
187,849✔
2576

2577
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
187,849✔
2578
   n->kind    = VCODE_TYPE_POINTER;
187,849✔
2579
   n->pointed = to;
187,849✔
2580

2581
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
187,849✔
2582
                "cannot get pointer to carray type");
2583

2584
   return vtype_new(n);
187,849✔
2585
}
2586

2587
vcode_type_t vtype_access(vcode_type_t to)
4,934✔
2588
{
2589
   assert(active_unit != NULL);
4,934✔
2590

2591
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
4,934✔
2592
   n->kind    = VCODE_TYPE_ACCESS;
4,934✔
2593
   n->pointed = to;
4,934✔
2594

2595
   return vtype_new(n);
4,934✔
2596
}
2597

2598
vcode_type_t vtype_signal(vcode_type_t base)
38,567✔
2599
{
2600
   assert(active_unit != NULL);
38,567✔
2601

2602
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
38,567✔
2603
   n->kind = VCODE_TYPE_SIGNAL;
38,567✔
2604
   n->base = base;
38,567✔
2605

2606
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
38,567✔
2607

2608
   return vtype_new(n);
38,567✔
2609
}
2610

2611
vcode_type_t vtype_resolution(vcode_type_t base)
959✔
2612
{
2613
   assert(active_unit != NULL);
959✔
2614

2615
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
959✔
2616
   n->kind = VCODE_TYPE_RESOLUTION;
959✔
2617
   n->base = base;
959✔
2618

2619
   return vtype_new(n);
959✔
2620
}
2621

2622
vcode_type_t vtype_closure(vcode_type_t result)
1,322✔
2623
{
2624
   assert(active_unit != NULL);
1,322✔
2625

2626
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,322✔
2627
   n->kind = VCODE_TYPE_CLOSURE;
1,322✔
2628
   n->base = result;
1,322✔
2629

2630
   return vtype_new(n);
1,322✔
2631
}
2632

2633
vcode_type_t vtype_context(ident_t name)
52,184✔
2634
{
2635
   assert(active_unit != NULL);
52,184✔
2636
   assert(name != NULL);
52,184✔
2637

2638
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
52,184✔
2639
   n->kind = VCODE_TYPE_CONTEXT;
52,184✔
2640
   n->name = name;
52,184✔
2641

2642
   return vtype_new(n);
52,184✔
2643
}
2644

2645
vcode_type_t vtype_file(vcode_type_t base)
610✔
2646
{
2647
   assert(active_unit != NULL);
610✔
2648

2649
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
610✔
2650
   n->kind = VCODE_TYPE_FILE;
610✔
2651
   n->base = base;
610✔
2652

2653
   return vtype_new(n);
610✔
2654
}
2655

2656
vcode_type_t vtype_offset(void)
267,404✔
2657
{
2658
   assert(active_unit != NULL);
267,404✔
2659

2660
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
267,404✔
2661
   n->kind = VCODE_TYPE_OFFSET;
267,404✔
2662
   n->low  = INT64_MIN;
267,404✔
2663
   n->high = INT64_MAX;
267,404✔
2664
   n->repr = VCODE_REPR_I64;
267,404✔
2665

2666
   return vtype_new(n);
267,404✔
2667
}
2668

2669
vcode_type_t vtype_time(void)
17,312✔
2670
{
2671
   return vtype_int(INT64_MIN, INT64_MAX);
17,312✔
2672
}
2673

2674
vcode_type_t vtype_char(void)
9,315✔
2675
{
2676
   return vtype_int(0, 255);
9,315✔
2677
}
2678

2679
vcode_type_t vtype_opaque(void)
1,466✔
2680
{
2681
   assert(active_unit != NULL);
1,466✔
2682

2683
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,466✔
2684
   n->kind = VCODE_TYPE_OPAQUE;
1,466✔
2685

2686
   return vtype_new(n);
1,466✔
2687
}
2688

2689
vcode_type_t vtype_debug_locus(void)
110,173✔
2690
{
2691
   assert(active_unit != NULL);
110,173✔
2692

2693
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
110,173✔
2694
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
110,173✔
2695

2696
   return vtype_new(n);
110,173✔
2697
}
2698

2699
vcode_type_t vtype_trigger(void)
383✔
2700
{
2701
   assert(active_unit != NULL);
383✔
2702

2703
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
383✔
2704
   n->kind = VCODE_TYPE_TRIGGER;
383✔
2705

2706
   return vtype_new(n);
383✔
2707
}
2708

2709
vcode_type_t vtype_conversion(void)
558✔
2710
{
2711
   assert(active_unit != NULL);
558✔
2712

2713
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
558✔
2714
   n->kind = VCODE_TYPE_CONVERSION;
558✔
2715

2716
   return vtype_new(n);
558✔
2717
}
2718

2719
vcode_type_t vtype_real(double low, double high)
80,755✔
2720
{
2721
   assert(active_unit != NULL);
80,755✔
2722

2723
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
80,755✔
2724
   n->kind  = VCODE_TYPE_REAL;
80,755✔
2725
   n->rlow  = low;
80,755✔
2726
   n->rhigh = high;
80,755✔
2727

2728
   return vtype_new(n);
80,755✔
2729
}
2730

2731
vtype_kind_t vtype_kind(vcode_type_t type)
5,746,904✔
2732
{
2733
   vtype_t *vt = vcode_type_data(type);
5,746,904✔
2734
   return vt->kind;
5,746,904✔
2735
}
2736

2737
vtype_repr_t vtype_repr(vcode_type_t type)
467,272✔
2738
{
2739
   vtype_t *vt = vcode_type_data(type);
467,272✔
2740
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
467,272✔
2741
   return vt->repr;
467,272✔
2742
}
2743

2744
vcode_type_t vtype_elem(vcode_type_t type)
358,019✔
2745
{
2746
   vtype_t *vt = vcode_type_data(type);
358,019✔
2747
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
358,019✔
2748
   return vt->elem;
358,019✔
2749
}
2750

2751
vcode_type_t vtype_base(vcode_type_t type)
15,395✔
2752
{
2753
   vtype_t *vt = vcode_type_data(type);
15,395✔
2754
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
15,395✔
2755
          || vt->kind == VCODE_TYPE_RESOLUTION
2756
          || vt->kind == VCODE_TYPE_CLOSURE);
2757
   return vt->base;
15,395✔
2758
}
2759

2760
vcode_type_t vtype_bounds(vcode_type_t type)
12,776✔
2761
{
2762
   vtype_t *vt = vcode_type_data(type);
12,776✔
2763
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
12,776✔
2764
   return vt->bounds;
12,776✔
2765
}
2766

2767
unsigned vtype_dims(vcode_type_t type)
137,923✔
2768
{
2769
   vtype_t *vt = vcode_type_data(type);
137,923✔
2770
   assert(vt->kind == VCODE_TYPE_UARRAY);
137,923✔
2771
   return vt->dims;
137,923✔
2772
}
2773

2774
unsigned vtype_size(vcode_type_t type)
77,681✔
2775
{
2776
   vtype_t *vt = vcode_type_data(type);
77,681✔
2777
   assert(vt->kind == VCODE_TYPE_CARRAY);
77,681✔
2778
   return vt->size;
77,681✔
2779
}
2780

2781
int vtype_fields(vcode_type_t type)
26,059✔
2782
{
2783
   vtype_t *vt = vcode_type_data(type);
26,059✔
2784
   assert(vt->kind == VCODE_TYPE_RECORD);
26,059✔
2785
   return vt->fields.count;
26,059✔
2786
}
2787

2788
vcode_type_t vtype_field(vcode_type_t type, int field)
212,605✔
2789
{
2790
   vtype_t *vt = vcode_type_data(type);
212,605✔
2791
   assert(vt->kind == VCODE_TYPE_RECORD);
212,605✔
2792
   return vcode_type_array_nth(&(vt->fields), field);
212,605✔
2793
}
2794

2795
ident_t vtype_name(vcode_type_t type)
2,666✔
2796
{
2797
   vtype_t *vt = vcode_type_data(type);
2,666✔
2798
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
2,666✔
2799
   return vt->name;
2,666✔
2800
}
2801

2802
vcode_type_t vtype_pointed(vcode_type_t type)
388,257✔
2803
{
2804
   vtype_t *vt = vcode_type_data(type);
388,257✔
2805
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
388,257✔
2806
   return vt->pointed;
388,257✔
2807
}
2808

2809
int64_t vtype_low(vcode_type_t type)
61,558✔
2810
{
2811
   vtype_t *vt = vcode_type_data(type);
61,558✔
2812
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
61,558✔
2813
   return vt->low;
61,558✔
2814
}
2815

2816
int64_t vtype_high(vcode_type_t type)
59,386✔
2817
{
2818
   vtype_t *vt = vcode_type_data(type);
59,386✔
2819
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
59,386✔
2820
   return vt->high;
59,386✔
2821
}
2822

2823
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
454✔
2824
{
2825
   return vtype_kind(type) == VCODE_TYPE_POINTER
454✔
2826
      && vtype_kind(vtype_pointed(type)) == to;
454✔
2827
}
2828

2829
bool vtype_is_scalar(vcode_type_t type)
404,460✔
2830
{
2831
   const vtype_kind_t kind = vtype_kind(type);
404,460✔
2832
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
404,460✔
2833
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
161,492✔
2834
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2835
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2836
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER;
404,460✔
2837
}
2838

2839
bool vtype_is_composite(vcode_type_t type)
23,114✔
2840
{
2841
   const vtype_kind_t kind = vtype_kind(type);
23,114✔
2842
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
23,114✔
2843
}
2844

2845
bool vtype_is_signal(vcode_type_t type)
170,666✔
2846
{
2847
   vtype_t *vt = vcode_type_data(type);
301,453✔
2848
   switch (vt->kind) {
301,453✔
2849
   case VCODE_TYPE_SIGNAL:
2850
      return true;
2851
   case VCODE_TYPE_POINTER:
71,770✔
2852
      return vtype_is_signal(vt->pointed);
71,770✔
2853
   case VCODE_TYPE_RECORD:
2854
      for (int i = 0; i < vt->fields.count; i++) {
36,584✔
2855
         if (vtype_is_signal(vt->fields.items[i]))
28,585✔
2856
            return true;
2857
      }
2858
      return false;
2859
   case VCODE_TYPE_UARRAY:
59,017✔
2860
   case VCODE_TYPE_CARRAY:
2861
      return vtype_is_signal(vt->elem);
59,017✔
2862
   default:
134,533✔
2863
      return false;
134,533✔
2864
   }
2865
}
2866

2867
int vtype_repr_bits(vtype_repr_t repr)
369,194✔
2868
{
2869
   switch (repr) {
369,194✔
2870
   case VCODE_REPR_U1: return 1;
2871
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2872
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2873
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2874
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2875
   default: return -1;
2876
   }
2877
}
2878

2879
bool vtype_repr_signed(vtype_repr_t repr)
47,193✔
2880
{
2881
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
47,193✔
2882
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
47,193✔
2883
}
2884

2885
static int64_t vtype_repr_low(vtype_repr_t repr)
8,746✔
2886
{
2887
   switch (repr) {
8,746✔
2888
   case VCODE_REPR_U1:
2889
   case VCODE_REPR_U8:
2890
   case VCODE_REPR_U16:
2891
   case VCODE_REPR_U32:
2892
   case VCODE_REPR_U64: return 0;
2893
   case VCODE_REPR_I8:  return INT8_MIN;
2894
   case VCODE_REPR_I16: return INT16_MIN;
2895
   case VCODE_REPR_I32: return INT32_MIN;
2896
   case VCODE_REPR_I64: return INT64_MIN;
2897
   default:             return 0;
2898
   }
2899
}
2900

2901
static uint64_t vtype_repr_high(vtype_repr_t repr)
8,746✔
2902
{
2903
   switch (repr) {
8,746✔
2904
   case VCODE_REPR_U1:  return 1;
2905
   case VCODE_REPR_U8:  return UINT8_MAX;
2906
   case VCODE_REPR_U16: return UINT16_MAX;
2907
   case VCODE_REPR_U32: return UINT32_MAX;
2908
   case VCODE_REPR_U64: return UINT64_MAX;
2909
   case VCODE_REPR_I8:  return INT8_MAX;
2910
   case VCODE_REPR_I16: return INT16_MAX;
2911
   case VCODE_REPR_I32: return INT32_MAX;
2912
   case VCODE_REPR_I64: return INT64_MAX;
2913
   default:             return 0;
2914
   }
2915
}
2916

2917
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
8,746✔
2918
{
2919
   int64_t clamp_low = vtype_repr_low(repr);
8,746✔
2920
   uint64_t clamp_high = vtype_repr_high(repr);
8,746✔
2921

2922
   if (*low >= clamp_low && *high <= clamp_high)
8,746✔
2923
      return true;
2924
   else {
2925
      *low = MAX(clamp_low, *low);
4,643✔
2926
      *high = MIN(clamp_high, *high);
4,643✔
2927
      return false;
4,643✔
2928
   }
2929
}
2930

2931
int vcode_count_params(void)
11,487✔
2932
{
2933
   assert(active_unit != NULL);
11,487✔
2934
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
11,487✔
2935
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2936
          || active_unit->kind == VCODE_UNIT_PROPERTY
2937
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2938

2939
   return active_unit->params.count;
11,487✔
2940
}
2941

2942
vcode_type_t vcode_param_type(int param)
29,872✔
2943
{
2944
   assert(active_unit != NULL);
29,872✔
2945
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
29,872✔
2946
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2947
          || active_unit->kind == VCODE_UNIT_PROPERTY
2948
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2949
   assert(param < active_unit->params.count);
29,872✔
2950

2951
   return active_unit->params.items[param].type;
29,872✔
2952
}
2953

2954
vcode_reg_t vcode_param_reg(int param)
37,915✔
2955
{
2956
   assert(active_unit != NULL);
37,915✔
2957
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
37,915✔
2958
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2959
          || active_unit->kind == VCODE_UNIT_PROPERTY
2960
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2961
   assert(param < active_unit->params.count);
37,915✔
2962

2963
   return active_unit->params.items[param].reg;
37,915✔
2964
}
2965

2966
vcode_block_t emit_block(void)
139,025✔
2967
{
2968
   assert(active_unit != NULL);
139,025✔
2969

2970
   vcode_block_t bnum = active_unit->blocks.count;
139,025✔
2971

2972
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
139,025✔
2973
   memset(bptr, '\0', sizeof(block_t));
139,025✔
2974

2975
   if (active_block != VCODE_INVALID_BLOCK)
139,025✔
2976
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
94,375✔
2977
   else
2978
      bptr->last_loc = LOC_INVALID;
44,650✔
2979

2980
   return bnum;
139,025✔
2981
}
2982

2983
void vcode_select_unit(vcode_unit_t unit)
178,436✔
2984
{
2985
   active_unit  = unit;
178,436✔
2986
   active_block = VCODE_INVALID_BLOCK;
178,436✔
2987
}
178,436✔
2988

2989
void vcode_select_block(vcode_block_t block)
579,370✔
2990
{
2991
   assert(active_unit != NULL);
579,370✔
2992
   active_block = block;
579,370✔
2993
}
579,370✔
2994

2995
vcode_block_t vcode_active_block(void)
1,489,737✔
2996
{
2997
   assert(active_unit != NULL);
1,489,737✔
2998
   assert(active_block != -1);
1,489,737✔
2999
   return active_block;
1,489,737✔
3000
}
3001

3002
const loc_t *vcode_last_loc(void)
654,423✔
3003
{
3004
   return &(vcode_block_data()->last_loc);
654,423✔
3005
}
3006

3007
vcode_unit_t vcode_active_unit(void)
871✔
3008
{
3009
   assert(active_unit != NULL);
871✔
3010
   return active_unit;
871✔
3011
}
3012

3013
ident_t vcode_unit_name(vcode_unit_t vu)
163,742✔
3014
{
3015
   assert(vu != NULL);
163,742✔
3016
   return vu->name;
163,742✔
3017
}
3018

3019
bool vcode_unit_has_undefined(vcode_unit_t vu)
12,385✔
3020
{
3021
   assert(vu != NULL);
12,385✔
3022
   return !!(vu->flags & UNIT_UNDEFINED);
12,385✔
3023
}
3024

3025
bool vcode_unit_has_escaping_tlab(vcode_unit_t vu)
4,743✔
3026
{
3027
   return !!(vu->flags & UNIT_ESCAPING_TLAB);
4,743✔
3028
}
3029

UNCOV
3030
int vcode_unit_depth(vcode_unit_t vu)
×
3031
{
UNCOV
3032
   assert(vu != NULL);
×
UNCOV
3033
   return vu->depth;
×
3034
}
3035

3036
void vcode_set_result(vcode_type_t type)
22,115✔
3037
{
3038
   assert(active_unit != NULL);
22,115✔
3039
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
22,115✔
3040
          || active_unit->kind == VCODE_UNIT_THUNK);
3041

3042
   active_unit->result = type;
22,115✔
3043
}
22,115✔
3044

3045
vcode_type_t vcode_unit_result(vcode_unit_t vu)
21,473✔
3046
{
3047
   assert(vu != NULL);
21,473✔
3048
   assert(vu->kind == VCODE_UNIT_FUNCTION || vu->kind == VCODE_UNIT_THUNK);
21,473✔
3049
   return vu->result;
21,473✔
3050
}
3051

3052
vunit_kind_t vcode_unit_kind(vcode_unit_t vu)
369,941✔
3053
{
3054
   assert(vu != NULL);
369,941✔
3055
   return vu->kind;
369,941✔
3056
}
3057

3058
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
137,440✔
3059
{
3060
   assert(vu != NULL);
137,440✔
3061
   return vu->context;
137,440✔
3062
}
3063

3064
object_t *vcode_unit_object(vcode_unit_t vu)
77,554✔
3065
{
3066
   assert(vu != NULL);
77,554✔
3067
   return vu->object;
77,554✔
3068
}
3069

3070
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
57,044✔
3071
{
3072
   int hops = 0;
57,044✔
3073
   for (; (unit = unit->context); hops++)
146,559✔
3074
      ;
3075
   return hops;
57,044✔
3076
}
3077

3078
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
27,908✔
3079
{
3080
   assert(context->kind != VCODE_UNIT_THUNK);
27,908✔
3081

3082
   child->next = NULL;
27,908✔
3083
   if (context->children == NULL)
27,908✔
3084
      context->children = child;
11,317✔
3085
   else {
3086
      vcode_unit_t it;
3087
      for (it = context->children; it->next != NULL; it = it->next)
755,243✔
3088
         ;
3089
      it->next = child;
16,591✔
3090
   }
3091
}
27,908✔
3092

3093
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
11,175✔
3094
{
3095
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
11,175✔
3096
   vu->kind     = VCODE_UNIT_FUNCTION;
11,175✔
3097
   vu->name     = name;
11,175✔
3098
   vu->context  = context;
11,175✔
3099
   vu->result   = VCODE_INVALID_TYPE;
11,175✔
3100
   vu->depth    = vcode_unit_calc_depth(vu);
11,175✔
3101
   vu->object   = obj;
11,175✔
3102

3103
   vcode_add_child(context, vu);
11,175✔
3104

3105
   vcode_select_unit(vu);
11,175✔
3106
   vcode_select_block(emit_block());
11,175✔
3107
   emit_debug_info(&(obj->loc));
11,175✔
3108

3109
   return vu;
11,175✔
3110
}
3111

3112
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
254✔
3113
{
3114
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
254✔
3115
   vu->kind     = VCODE_UNIT_PROCEDURE;
254✔
3116
   vu->name     = name;
254✔
3117
   vu->context  = context;
254✔
3118
   vu->result   = VCODE_INVALID_TYPE;
254✔
3119
   vu->depth    = vcode_unit_calc_depth(vu);
254✔
3120
   vu->object   = obj;
254✔
3121

3122
   vcode_add_child(context, vu);
254✔
3123

3124
   vcode_select_unit(vu);
254✔
3125
   vcode_select_block(emit_block());
254✔
3126
   emit_debug_info(&(obj->loc));
254✔
3127

3128
   return vu;
254✔
3129
}
3130

3131
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
9,209✔
3132
{
3133
   assert(context->kind == VCODE_UNIT_INSTANCE
9,209✔
3134
          || context->kind == VCODE_UNIT_SHAPE);
3135

3136
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,209✔
3137
   vu->kind     = VCODE_UNIT_PROCESS;
9,209✔
3138
   vu->name     = name;
9,209✔
3139
   vu->context  = context;
9,209✔
3140
   vu->depth    = vcode_unit_calc_depth(vu);
9,209✔
3141
   vu->result   = VCODE_INVALID_TYPE;
9,209✔
3142
   vu->object   = obj;
9,209✔
3143

3144
   vcode_add_child(context, vu);
9,209✔
3145

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

3150
   return vu;
9,209✔
3151
}
3152

3153
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
9,368✔
3154
{
3155
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
9,368✔
3156

3157
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,368✔
3158
   vu->kind     = VCODE_UNIT_INSTANCE;
9,368✔
3159
   vu->name     = name;
9,368✔
3160
   vu->context  = context;
9,368✔
3161
   vu->depth    = vcode_unit_calc_depth(vu);
9,368✔
3162
   vu->result   = VCODE_INVALID_TYPE;
9,368✔
3163
   vu->object   = obj;
9,368✔
3164

3165
   if (context != NULL)
9,368✔
3166
      vcode_add_child(context, vu);
5,794✔
3167

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

3172
   return vu;
9,368✔
3173
}
3174

3175
vcode_unit_t emit_shape(ident_t name, object_t *obj, vcode_unit_t context)
89✔
3176
{
3177
   assert(context == NULL || context->kind == VCODE_UNIT_SHAPE);
89✔
3178

3179
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
89✔
3180
   vu->kind     = VCODE_UNIT_SHAPE;
89✔
3181
   vu->name     = name;
89✔
3182
   vu->context  = context;
89✔
3183
   vu->depth    = vcode_unit_calc_depth(vu);
89✔
3184
   vu->result   = VCODE_INVALID_TYPE;
89✔
3185
   vu->object   = obj;
89✔
3186

3187
   if (context != NULL)
89✔
UNCOV
3188
      vcode_add_child(context, vu);
×
3189

3190
   vcode_select_unit(vu);
89✔
3191
   vcode_select_block(emit_block());
89✔
3192
   emit_debug_info(&(obj->loc));
89✔
3193

3194
   return vu;
89✔
3195
}
3196

3197
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
1,779✔
3198
{
3199
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
1,779✔
3200
   vu->kind     = VCODE_UNIT_PACKAGE;
1,779✔
3201
   vu->name     = name;
1,779✔
3202
   vu->context  = context;
1,779✔
3203
   vu->depth    = vcode_unit_calc_depth(vu);
1,779✔
3204
   vu->result   = VCODE_INVALID_TYPE;
1,779✔
3205
   vu->object   = obj;
1,779✔
3206

3207
   if (context != NULL)
1,779✔
3208
      vcode_add_child(context, vu);
182✔
3209

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

3214
   return vu;
1,779✔
3215
}
3216

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

3227
   if (context != NULL)
175✔
3228
      vcode_add_child(context, vu);
175✔
3229

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

3234
   return vu;
175✔
3235
}
3236

3237
vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context)
207✔
3238
{
3239
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
207✔
3240
   vu->kind     = VCODE_UNIT_PROPERTY;
207✔
3241
   vu->name     = name;
207✔
3242
   vu->context  = context;
207✔
3243
   vu->depth    = vcode_unit_calc_depth(vu);
207✔
3244
   vu->result   = VCODE_INVALID_TYPE;
207✔
3245
   vu->object   = obj;
207✔
3246

3247
   if (context != NULL)
207✔
3248
      vcode_add_child(context, vu);
207✔
3249

3250
   vcode_select_unit(vu);
207✔
3251
   vcode_select_block(emit_block());
207✔
3252
   emit_debug_info(&(obj->loc));
207✔
3253

3254
   return vu;
207✔
3255
}
3256

3257
vcode_unit_t emit_thunk(ident_t name, object_t *obj, vcode_unit_t context)
12,394✔
3258
{
3259
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
12,394✔
3260
   vu->kind     = VCODE_UNIT_THUNK;
12,394✔
3261
   vu->name     = name;
12,394✔
3262
   vu->context  = context;
12,394✔
3263
   vu->depth    = vcode_unit_calc_depth(vu);
12,394✔
3264
   vu->result   = VCODE_INVALID_TYPE;
12,394✔
3265
   vu->depth    = vcode_unit_calc_depth(vu);
12,394✔
3266
   vu->object   = obj;
12,394✔
3267

3268
   if (context != NULL)
12,394✔
3269
      vcode_add_child(context, vu);
912✔
3270

3271
   vcode_select_unit(vu);
12,394✔
3272
   vcode_select_block(emit_block());
12,394✔
3273

3274
   return vu;
12,394✔
3275
}
3276

3277
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
14,094✔
3278
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3279
                 vcode_reg_t hint_right)
3280
{
3281
   int64_t value_const;
14,094✔
3282
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
14,094✔
3283
      emit_comment("Always true assertion on r%d", value);
30✔
3284
      return;
30✔
3285
   }
3286

3287
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
14,064✔
3288
   vcode_add_arg(op, value);
14,064✔
3289
   vcode_add_arg(op, severity);
14,064✔
3290
   vcode_add_arg(op, message);
14,064✔
3291
   vcode_add_arg(op, length);
14,064✔
3292
   vcode_add_arg(op, locus);
14,064✔
3293

3294
   if (hint_left != VCODE_INVALID_REG) {
14,064✔
3295
      vcode_add_arg(op, hint_left);
5,767✔
3296
      vcode_add_arg(op, hint_right);
5,767✔
3297

3298
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
5,767✔
3299
                   "left hint must be scalar");
3300
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
5,767✔
3301
                   "right hint must be scalar");
3302
   }
3303

3304
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
14,064✔
3305
                "value parameter to assert is not bool");
3306
   VCODE_ASSERT(message == VCODE_INVALID_REG
14,064✔
3307
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3308
                "message parameter to assert is not a pointer");
3309
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
14,064✔
3310
                "value parameter to assert is not bool");
3311
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
14,064✔
3312
                "locus argument to report must be a debug locus");
3313
}
3314

3315
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,282✔
3316
                 vcode_reg_t locus)
3317
{
3318
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,282✔
3319
   vcode_add_arg(op, severity);
2,282✔
3320
   vcode_add_arg(op, message);
2,282✔
3321
   vcode_add_arg(op, length);
2,282✔
3322
   vcode_add_arg(op, locus);
2,282✔
3323

3324
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,282✔
3325
                "message parameter to report is not a pointer");
3326
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,282✔
3327
                "message parameter to report is not a character pointer");
3328
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,282✔
3329
                "locus argument to report must be a debug locus");
3330
}
2,282✔
3331

3332
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
38,624✔
3333
{
3334
   if (lhs == rhs) {
38,624✔
3335
      if (cmp == VCODE_CMP_EQ)
931✔
3336
         return emit_const(vtype_bool(), 1);
924✔
3337
      else if (cmp == VCODE_CMP_NEQ)
7✔
UNCOV
3338
         return emit_const(vtype_bool(), 0);
×
3339
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
7✔
UNCOV
3340
         return emit_const(vtype_bool(), 1);
×
3341
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
7✔
3342
         return emit_const(vtype_bool(), 0);
7✔
3343
   }
3344

3345
   int64_t lconst, rconst;
37,693✔
3346
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
37,693✔
3347
      switch (cmp) {
515✔
3348
      case VCODE_CMP_EQ:
307✔
3349
         return emit_const(vtype_bool(), lconst == rconst);
307✔
3350
      case VCODE_CMP_NEQ:
3✔
3351
         return emit_const(vtype_bool(), lconst != rconst);
3✔
3352
      case VCODE_CMP_LT:
3✔
3353
         return emit_const(vtype_bool(), lconst < rconst);
3✔
3354
      case VCODE_CMP_GT:
202✔
3355
         return emit_const(vtype_bool(), lconst > rconst);
202✔
UNCOV
3356
      case VCODE_CMP_LEQ:
×
UNCOV
3357
         return emit_const(vtype_bool(), lconst <= rconst);
×
UNCOV
3358
      case VCODE_CMP_GEQ:
×
3359
         return emit_const(vtype_bool(), lconst >= rconst);
×
3360
      default:
×
3361
         fatal_trace("cannot fold comparison %d", cmp);
3362
      }
3363
   }
3364

3365
   // Reuse any previous operation in this block with the same arguments
3366
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
659,905✔
3367
      if (other->args.count == 2 && other->args.items[0] == lhs
27,446✔
3368
          && other->args.items[1] == rhs && other->cmp == cmp)
1,179✔
3369
         return other->result;
196✔
3370
   }
3371

3372
   op_t *op = vcode_add_op(VCODE_OP_CMP);
36,982✔
3373
   vcode_add_arg(op, lhs);
36,982✔
3374
   vcode_add_arg(op, rhs);
36,982✔
3375
   op->cmp    = cmp;
36,982✔
3376
   op->result = vcode_add_reg(vtype_bool());
36,982✔
3377

3378
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
36,982✔
3379
                "arguments to cmp are not the same type");
3380

3381
   return op->result;
3382
}
3383

3384
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_type_t bounds,
36,426✔
3385
                       const vcode_reg_t *args, int nargs)
3386
{
3387
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
36,426✔
3388
   o->func = func;
36,426✔
3389
   o->type = type;
36,426✔
3390
   for (int i = 0; i < nargs; i++)
142,820✔
3391
      vcode_add_arg(o, args[i]);
106,394✔
3392

3393
   for (int i = 0; i < nargs; i++)
142,820✔
3394
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
106,394✔
3395
                   "invalid argument to function");
3396

3397
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
36,426✔
3398
                "first argument to VHDL function must be context pointer");
3399

3400
   if (type == VCODE_INVALID_TYPE)
36,426✔
3401
      return (o->result = VCODE_INVALID_REG);
5,010✔
3402
   else {
3403
      o->result = vcode_add_reg(type);
31,416✔
3404

3405
      reg_t *rr = vcode_reg_data(o->result);
31,416✔
3406
      rr->bounds = bounds;
31,416✔
3407

3408
      return o->result;
31,416✔
3409
   }
3410
}
3411

3412
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
880✔
3413
                vcode_block_t resume_bb)
3414
{
3415
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
880✔
3416
   o->func = func;
880✔
3417
   for (int i = 0; i < nargs; i++)
3,121✔
3418
      vcode_add_arg(o, args[i]);
2,241✔
3419

3420
   vcode_block_array_add(&(o->targets), resume_bb);
880✔
3421

3422
   for (int i = 0; i < nargs; i++)
3,121✔
3423
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,241✔
3424
                   "invalid argument to procedure");
3425

3426
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
880✔
3427
                "first argument to VHDL procedure must be context pointer");
3428
}
880✔
3429

3430
vcode_reg_t emit_syscall(ident_t func, vcode_type_t type, vcode_type_t bounds,
423✔
3431
                         vcode_reg_t locus, const vcode_reg_t *args, int nargs)
3432
{
3433
   op_t *o = vcode_add_op(VCODE_OP_SYSCALL);
423✔
3434
   o->func = func;
423✔
3435
   o->type = type;
423✔
3436
   vcode_add_arg(o, locus);
423✔
3437
   for (int i = 0; i < nargs; i++)
498✔
3438
      vcode_add_arg(o, args[i]);
75✔
3439

3440
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
423✔
3441
                "locus argument to syscall must be a debug locus");
3442

3443
   for (int i = 0; i < nargs; i++)
498✔
3444
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG, "invalid argument to syscall");
75✔
3445

3446
   if (type == VCODE_INVALID_TYPE)
423✔
3447
      return (o->result = VCODE_INVALID_REG);
384✔
3448
   else {
3449
      o->result = vcode_add_reg(type);
39✔
3450

3451
      reg_t *rr = vcode_reg_data(o->result);
39✔
3452
      rr->bounds = bounds;
39✔
3453

3454
      return o->result;
39✔
3455
   }
3456
}
3457

3458
vcode_reg_t emit_alloc(vcode_type_t type, vcode_type_t bounds,
7,373✔
3459
                       vcode_reg_t count)
3460
{
3461
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
7,373✔
3462
   op->type    = type;
7,373✔
3463
   op->result  = vcode_add_reg(vtype_pointer(type));
7,373✔
3464
   vcode_add_arg(op, count);
7,373✔
3465

3466
   const vtype_kind_t tkind = vtype_kind(type);
7,373✔
3467
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
7,373✔
3468
                "alloca element type cannot be array");
3469
   VCODE_ASSERT(count != VCODE_INVALID_REG,
7,373✔
3470
                "alloca must have valid count argument");
3471

3472
   reg_t *r = vcode_reg_data(op->result);
7,373✔
3473
   r->bounds = bounds;
7,373✔
3474

3475
   return op->result;
7,373✔
3476
}
3477

3478
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
983,348✔
3479
{
3480
   // Reuse any previous constant in this block with the same type and value
3481
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
20,773,372✔
3482
      if (other->value == value && vtype_eq(type, other->type))
7,679,459✔
3483
         return other->result;
584,758✔
3484
   }
3485

3486
   op_t *op = vcode_add_op(VCODE_OP_CONST);
398,590✔
3487
   op->value  = value;
398,590✔
3488
   op->type   = type;
398,590✔
3489
   op->result = vcode_add_reg(type);
398,590✔
3490

3491
   vtype_kind_t type_kind = vtype_kind(type);
398,590✔
3492
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
398,590✔
3493
                "constant must have integer or offset type");
3494

3495
   reg_t *r = vcode_reg_data(op->result);
398,590✔
3496
   r->bounds = vtype_int(value, value);
398,590✔
3497

3498
   return op->result;
398,590✔
3499
}
3500

3501
vcode_reg_t emit_const_real(vcode_type_t type, double value)
39,792✔
3502
{
3503
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
1,491,753✔
3504
      if (other->real == value && other->type == type)
932,929✔
3505
         return other->result;
13,222✔
3506
   }
3507

3508
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
26,570✔
3509
   op->real   = value;
26,570✔
3510
   op->type   = type;
26,570✔
3511
   op->result = vcode_add_reg(op->type);
26,570✔
3512

3513
   reg_t *r = vcode_reg_data(op->result);
26,570✔
3514
   r->bounds = vtype_real(value, value);
26,570✔
3515

3516
   return op->result;
26,570✔
3517
}
3518

3519
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
27,466✔
3520
{
3521
   vtype_kind_t kind = vtype_kind(type);
27,466✔
3522

3523
   // Reuse any previous operation in this block with the same arguments
3524
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,156,153✔
3525
      if (other->args.count != num)
116,757✔
3526
         continue;
69,606✔
3527
      else if (!vtype_eq(vcode_reg_type(other->result), type))
47,151✔
3528
         continue;
626✔
3529

3530
      bool match = true;
3531
      for (int i = 0; match && i < num; i++) {
294,846✔
3532
         if (other->args.items[i] != values[i])
248,321✔
3533
            match = false;
40,452✔
3534
      }
3535

3536
      if (match) return other->result;
46,525✔
3537
   }
3538

3539
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
21,393✔
3540
   op->result = vcode_add_reg(type);
21,393✔
3541

3542
   for (int i = 0; i < num; i++)
1,181,947✔
3543
      vcode_add_arg(op, values[i]);
1,160,554✔
3544

3545
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
21,393✔
3546
                "constant array must have constrained array type");
3547
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
21,393✔
3548
                vtype_size(type), num);
3549

3550
#ifdef DEBUG
3551
   vcode_type_t elem = vtype_elem(type);
21,393✔
3552
   for (int i = 0; i < num; i++) {
1,181,947✔
3553
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,160,554✔
3554
                   "wrong element type for item %d", i);
3555
      vcode_assert_const(values[i], "array");
1,160,554✔
3556
   }
3557
#endif
3558

3559
   reg_t *r = vcode_reg_data(op->result);
21,393✔
3560
   r->bounds = vtype_elem(type);
21,393✔
3561

3562
   return op->result;
21,393✔
3563
}
3564

3565
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
624✔
3566
{
3567
   // Reuse any previous operation in this block with the same arguments
3568
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
9,251✔
3569
      if (other->args.items[0] == value && other->value == rep)
972✔
3570
         return other->result;
264✔
3571
   }
3572

3573
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
360✔
3574
   op->value = rep;
360✔
3575
   vcode_add_arg(op, value);
360✔
3576

3577
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
360✔
3578
                "constant array must have constrained array type");
3579

3580
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
360✔
3581

3582
   op->result = vcode_add_reg(type);
360✔
3583

3584
   reg_t *r = vcode_reg_data(op->result);
360✔
3585
   r->bounds = vtype_bounds(type);
360✔
3586

3587
   return op->result;
360✔
3588
}
3589

3590
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
2,700✔
3591
{
3592
   // Reuse any previous constant in this block with the same type and value
3593
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
39,006✔
3594
      if (other->args.count == num && vtype_eq(type, other->type)) {
1,631✔
3595
         bool same_regs = true;
3596
         for (int i = 0; same_regs && i < num; i++)
2,459✔
3597
            same_regs = other->args.items[i] == values[i];
1,472✔
3598

3599
         if (same_regs)
987✔
3600
            return other->result;
223✔
3601
      }
3602
   }
3603

3604
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
2,477✔
3605
   op->type   = type;
2,477✔
3606
   op->result = vcode_add_reg(type);
2,477✔
3607

3608
   for (int i = 0; i < num; i++)
8,710✔
3609
      vcode_add_arg(op, values[i]);
6,233✔
3610

3611
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
2,477✔
3612
                "constant record must have record type");
3613

3614
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
2,477✔
3615
                vtype_fields(type), num);
3616

3617
#ifdef DEBUG
3618
   for (int i = 0; i < num; i++) {
8,710✔
3619
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
6,233✔
3620
                   "wrong type for field %d", i);
3621
      vcode_assert_const(values[i], "record");
6,233✔
3622
   }
3623
#endif
3624

3625
   return op->result;
2,477✔
3626
}
3627

3628
vcode_reg_t emit_address_of(vcode_reg_t value)
29,215✔
3629
{
3630
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
1,221,079✔
3631
      if (other->args.items[0] == value)
117,978✔
3632
         return other->result;
6,101✔
3633
   }
3634

3635
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
23,114✔
3636
   vcode_add_arg(op, value);
23,114✔
3637

3638
   vcode_type_t type = vcode_reg_type(value);
23,114✔
3639
   VCODE_ASSERT(vtype_is_composite(type),
23,114✔
3640
                "address of argument must be record or array");
3641

3642
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
23,114✔
3643
      vcode_type_t elem = vtype_elem(type);
21,184✔
3644
      op->result = vcode_add_reg(vtype_pointer(elem));
21,184✔
3645

3646
      reg_t *rr = vcode_reg_data(op->result);
21,184✔
3647
      rr->bounds = elem;
21,184✔
3648

3649
      return op->result;
21,184✔
3650
   }
3651
   else
3652
      return (op->result = vcode_add_reg(vtype_pointer(type)));
1,930✔
3653
}
3654

3655
void emit_wait(vcode_block_t target, vcode_reg_t time)
13,657✔
3656
{
3657
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
13,657✔
3658
   vcode_add_target(op, target);
13,657✔
3659
   vcode_add_arg(op, time);
13,657✔
3660

3661
   VCODE_ASSERT(time == VCODE_INVALID_REG
13,657✔
3662
                || vcode_reg_kind(time) == VCODE_TYPE_INT,
3663
                "wait time must have integer type");
3664
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
13,657✔
3665
                || active_unit->kind == VCODE_UNIT_PROCESS,
3666
                "wait only allowed in process or procedure");
3667
}
13,657✔
3668

3669
void emit_jump(vcode_block_t target)
35,809✔
3670
{
3671
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
35,809✔
3672
   vcode_add_target(op, target);
35,809✔
3673

3674
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
35,809✔
3675
}
35,809✔
3676

3677
vcode_var_t emit_var(vcode_type_t type, vcode_type_t bounds, ident_t name,
48,855✔
3678
                     vcode_var_flags_t flags)
3679
{
3680
   assert(active_unit != NULL);
48,855✔
3681

3682
   vcode_var_t var = active_unit->vars.count;
48,855✔
3683
   var_t *v = var_array_alloc(&(active_unit->vars));
48,855✔
3684
   memset(v, '\0', sizeof(var_t));
48,855✔
3685
   v->type     = type;
48,855✔
3686
   v->bounds   = bounds;
48,855✔
3687
   v->name     = name;
48,855✔
3688
   v->flags    = flags;
48,855✔
3689

3690
   return var;
48,855✔
3691
}
3692

3693
vcode_reg_t emit_param(vcode_type_t type, vcode_type_t bounds, ident_t name)
31,676✔
3694
{
3695
   assert(active_unit != NULL);
31,676✔
3696

3697
   param_t *p = param_array_alloc(&(active_unit->params));
31,676✔
3698
   memset(p, '\0', sizeof(param_t));
31,676✔
3699
   p->type   = type;
31,676✔
3700
   p->bounds = bounds;
31,676✔
3701
   p->name   = name;
31,676✔
3702
   p->reg    = vcode_add_reg(type);
31,676✔
3703

3704
   reg_t *rr = vcode_reg_data(p->reg);
31,676✔
3705
   rr->bounds = bounds;
31,676✔
3706

3707
   return p->reg;
31,676✔
3708
}
3709

3710
vcode_reg_t emit_load(vcode_var_t var)
52,069✔
3711
{
3712
   // Try scanning backwards through the block for another load or store to
3713
   // this variable
3714
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
52,069✔
3715
   vcode_reg_t fold = VCODE_INVALID_REG;
52,069✔
3716
   VCODE_FOR_EACH_OP(other) {
728,222✔
3717
      switch (state) {
690,436✔
3718
      case EAGER:
228,508✔
3719
         if (other->kind == VCODE_OP_LOAD && other->address == var)
228,508✔
3720
            return other->result;
3,044✔
3721
         else if (other->kind == VCODE_OP_STORE && other->address == var)
225,464✔
3722
            return other->args.items[0];
11,239✔
3723
         else if (other->kind == VCODE_OP_FCALL
214,225✔
3724
                  || other->kind == VCODE_OP_PCALL
214,225✔
3725
                  || other->kind == VCODE_OP_FILE_READ
3726
                  || other->kind == VCODE_OP_FILE_OPEN
3727
                  || other->kind == VCODE_OP_STORE_INDIRECT
3728
                  || other->kind == VCODE_OP_DEALLOCATE)
3729
            state = CONSERVATIVE;   // May write to variable
8,873✔
3730
         break;
3731

3732
      case CONSERVATIVE:
437,381✔
3733
         if (other->kind == VCODE_OP_LOAD && other->address == var
437,381✔
3734
             && fold == VCODE_INVALID_REG)
4,240✔
3735
            fold = other->result;
3,393✔
3736
         else if (other->kind == VCODE_OP_STORE && other->address == var
433,988✔
3737
                  && fold == VCODE_INVALID_REG)
2,561✔
3738
            fold = other->args.items[0];
2,430✔
3739
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
431,558✔
3740
            state = UNSAFE;
3741
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
430,564✔
3742
            state = UNSAFE;   // Nested call captures variables
80✔
3743
         break;
3744

3745
      case UNSAFE:
3746
         break;
3747
      }
3748
   }
3749

3750
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
37,786✔
3751
      return fold;
3752

3753
   var_t *v = vcode_var_data(var);
32,310✔
3754

3755
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
32,310✔
3756
   op->address = var;
32,310✔
3757
   op->result  = vcode_add_reg(v->type);
32,310✔
3758

3759
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
32,310✔
3760

3761
   reg_t *r = vcode_reg_data(op->result);
32,310✔
3762
   r->bounds = v->bounds;
32,310✔
3763

3764
   return op->result;
32,310✔
3765
}
3766

3767
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
95,003✔
3768
{
3769
   VCODE_FOR_EACH_OP(other) {
1,091,324✔
3770
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,024,198✔
3771
          && other->args.items[0] == reg) {
160,243✔
3772
         return other->result;
7,228✔
3773
      }
3774
      else if (other->kind == VCODE_OP_FCALL
1,016,970✔
3775
               || other->kind == VCODE_OP_PCALL
1,016,970✔
3776
               || other->kind == VCODE_OP_STORE
3777
               || other->kind == VCODE_OP_STORE_INDIRECT
3778
               || other->kind == VCODE_OP_MEMSET
3779
               || other->kind == VCODE_OP_COPY
3780
               || other->kind == VCODE_OP_FILE_READ)
3781
         break;   // May write to this pointer
3782
   }
3783

3784
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
87,775✔
3785
   vcode_add_arg(op, reg);
87,775✔
3786

3787
   vcode_type_t rtype = vcode_reg_type(reg);
87,775✔
3788

3789
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
87,775✔
3790
                "load indirect with non-pointer argument");
3791

3792
   vcode_type_t deref = vtype_pointed(rtype);
87,775✔
3793
   op->result = vcode_add_reg(deref);
87,775✔
3794

3795
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
87,775✔
3796

3797
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
87,775✔
3798

3799
   return op->result;
87,775✔
3800
}
3801

3802
void emit_store(vcode_reg_t reg, vcode_var_t var)
58,961✔
3803
{
3804
   // Any previous store to this variable in this block is dead
3805
   VCODE_FOR_EACH_OP(other) {
1,125,346✔
3806
      if (other->kind == VCODE_OP_STORE && other->address == var) {
1,078,246✔
3807
         other->kind = VCODE_OP_COMMENT;
258✔
3808
         other->comment =
516✔
3809
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
258✔
3810
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
258✔
3811
      }
3812
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
1,077,988✔
3813
         break;   // Needs to get variable for display
3814
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
1,072,038✔
3815
               && other->address == var)
25,096✔
3816
         break;   // Previous value may be used
3817
   }
3818

3819
   var_t *v = vcode_var_data(var);
58,961✔
3820
   reg_t *r = vcode_reg_data(reg);
58,961✔
3821

3822
   op_t *op = vcode_add_op(VCODE_OP_STORE);
58,961✔
3823
   vcode_add_arg(op, reg);
58,961✔
3824
   op->address = var;
58,961✔
3825

3826
   VCODE_ASSERT(vtype_eq(v->type, r->type),
58,961✔
3827
                "variable and stored value do not have same type");
3828
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
58,961✔
3829
}
58,961✔
3830

3831
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
13,767✔
3832
{
3833
   reg_t *p = vcode_reg_data(ptr);
13,767✔
3834
   reg_t *r = vcode_reg_data(reg);
13,767✔
3835

3836
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
13,767✔
3837
   vcode_add_arg(op, reg);
13,767✔
3838
   vcode_add_arg(op, ptr);
13,767✔
3839

3840
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
13,767✔
3841
                "store indirect target is not a pointer");
3842
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
13,767✔
3843
                "pointer and stored value do not have same type");
3844
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
13,767✔
3845
}
13,767✔
3846

3847
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
50,556✔
3848
                              vcode_reg_t locus)
3849
{
3850
   // Reuse any previous operation in this block with the same arguments
3851
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,051,229✔
3852
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
59,235✔
3853
         return other->result;
2,867✔
3854
   }
3855

3856
   op_t *op = vcode_add_op(kind);
47,689✔
3857
   vcode_add_arg(op, lhs);
47,689✔
3858
   vcode_add_arg(op, rhs);
47,689✔
3859
   if (locus != VCODE_INVALID_REG)
47,689✔
3860
      vcode_add_arg(op, locus);
4,991✔
3861

3862
   op->result = vcode_add_reg(vcode_reg_type(lhs));
47,689✔
3863

3864
   vcode_type_t lhs_type = vcode_reg_type(lhs);
47,689✔
3865
   vcode_type_t rhs_type = vcode_reg_type(rhs);
47,689✔
3866

3867
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
47,689✔
3868
                "arguments to %s are not the same type", vcode_op_string(kind));
3869

3870
   return op->result;
3871
}
3872

3873
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
34,689✔
3874
                               vcode_reg_t locus)
3875
{
3876
   int64_t lconst, rconst;
34,689✔
3877
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
34,689✔
3878
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
34,689✔
3879
   if (l_is_const && r_is_const)
34,689✔
3880
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
19,463✔
3881
   else if (r_is_const && rconst == 1)
15,226✔
3882
      return lhs;
3883
   else if (l_is_const && lconst == 1)
3,545✔
3884
      return rhs;
3885
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
3,070✔
3886
      return emit_const(vcode_reg_type(lhs), 0);
51✔
3887

3888
   reg_t *lhs_r = vcode_reg_data(lhs);
3,019✔
3889
   reg_t *rhs_r = vcode_reg_data(rhs);
3,019✔
3890

3891
   vtype_t *bl = vcode_type_data(lhs_r->bounds);
3,019✔
3892
   vtype_t *br = vcode_type_data(rhs_r->bounds);
3,019✔
3893

3894
   vcode_type_t vbounds;
3,019✔
3895
   if (vcode_reg_kind(lhs) == VCODE_TYPE_REAL) {
3,019✔
3896
      const double ll = bl->rlow * br->rlow;
740✔
3897
      const double lh = bl->rlow * br->rhigh;
740✔
3898
      const double hl = bl->rhigh * br->rlow;
740✔
3899
      const double hh = bl->rhigh * br->rhigh;
740✔
3900

3901
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,596✔
3902
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,818✔
3903

3904
      vbounds = vtype_real(min, max);
740✔
3905
   }
3906
   else {
3907
      const int64_t ll = smul64(bl->low, br->low);
2,279✔
3908
      const int64_t lh = smul64(bl->low, br->high);
2,279✔
3909
      const int64_t hl = smul64(bl->high, br->low);
2,279✔
3910
      const int64_t hh = smul64(bl->high, br->high);
2,279✔
3911

3912
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
2,279✔
3913
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
2,279✔
3914

3915
      vtype_repr_t repr = vtype_repr(lhs_r->type);
2,279✔
3916
      if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
2,279✔
3917
         op = VCODE_OP_MUL;   // Cannot overflow
400✔
3918
         locus = VCODE_INVALID_REG;
400✔
3919
      }
3920

3921
      vbounds = vtype_int(min, max);
2,279✔
3922
   }
3923

3924
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
3,019✔
3925

3926
   if (vbounds != VCODE_INVALID_TYPE)
3,019✔
3927
      vcode_reg_data(reg)->bounds = vbounds;
3,019✔
3928

3929
   return reg;
3930
}
3931

3932
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
33,789✔
3933
{
3934
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
33,789✔
3935
}
3936

3937
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
900✔
3938
{
3939
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
900✔
3940

3941
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
900✔
3942
                "trapping add may only be used with integer types");
3943

3944
   return result;
900✔
3945
}
3946

3947
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
1,025✔
3948
{
3949
   int64_t lconst, rconst;
1,025✔
3950
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
1,025✔
3951
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
1,025✔
3952
   if (l_is_const && r_is_const && rconst != 0)
1,025✔
3953
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
32✔
3954
   else if (r_is_const && rconst == 1)
993✔
3955
      return lhs;
3956

3957
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
992✔
3958

3959
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
992✔
3960

3961
   if (bl->kind == VCODE_TYPE_INT && r_is_const && rconst != 0) {
992✔
3962
      reg_t *rr = vcode_reg_data(reg);
699✔
3963
      rr->bounds = vtype_int(bl->low / rconst, bl->high / rconst);
699✔
3964
   }
3965
   else if (bl->kind == VCODE_TYPE_REAL) {
293✔
3966
      reg_t *rr = vcode_reg_data(reg);
225✔
3967
      rr->bounds = vtype_real(-INFINITY, INFINITY);
225✔
3968
   }
3969

3970
   return reg;
3971
}
3972

3973
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
79✔
3974
{
3975
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
79✔
3976
}
3977

3978
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
816✔
3979
{
3980
   int64_t rconst;
816✔
3981
   if (vcode_reg_const(rhs, &rconst)) {
816✔
3982
      if (rconst == 0)
707✔
3983
         return emit_const(vcode_reg_type(lhs), 1);
223✔
3984
      else if (rconst == 1)
484✔
3985
         return lhs;
3986
   }
3987

3988
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
544✔
3989

3990
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
544✔
3991
                "trapping exp may only be used with integer types");
3992

3993
   return result;
3994
}
3995

3996
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
222✔
3997
{
3998
   int64_t lconst, rconst;
222✔
3999
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
222✔
4000
       && lconst > 0 && rconst > 0)
15✔
4001
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
3✔
4002

4003
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
219✔
4004
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
219✔
4005

4006
   if (bl->low >= 0 && br->low >= 0) {
219✔
4007
      // If both arguments are non-negative then rem is equivalent and
4008
      // cheaper to compute
4009
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
48✔
4010

4011
      reg_t *rr = vcode_reg_data(reg);
48✔
4012
      rr->bounds = vtype_int(0, MAX(0, br->high - 1));
48✔
4013

4014
      return reg;
48✔
4015
   }
4016
   else
4017
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
171✔
4018
}
4019

4020
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
95✔
4021
{
4022
   int64_t lconst, rconst;
95✔
4023
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
95✔
4024
       && lconst > 0 && rconst > 0)
2✔
UNCOV
4025
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
4026

4027
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
95✔
4028

4029
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
95✔
4030
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
95✔
4031

4032
   if (bl->low >= 0 && br->low >= 0) {
95✔
4033
      reg_t *rr = vcode_reg_data(reg);
36✔
4034
      rr->bounds = vtype_int(0, br->high - 1);
36✔
4035
   }
4036

4037
   return reg;
4038
}
4039

4040
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
43,295✔
4041
                               vcode_reg_t locus)
4042
{
4043
   int64_t lconst, rconst;
43,295✔
4044
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
43,295✔
4045
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
43,295✔
4046
   if (l_is_const && r_is_const)
43,295✔
4047
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
17,370✔
4048
   else if (r_is_const && rconst == 0)
25,925✔
4049
      return lhs;
4050
   else if (l_is_const && lconst == 0)
25,919✔
4051
      return rhs;
4052

4053
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
16,043✔
4054
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
16,043✔
4055
      reg_t *lhs_r = vcode_reg_data(lhs);
15,756✔
4056
      reg_t *rhs_r = vcode_reg_data(rhs);
15,756✔
4057

4058
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
15,756✔
4059
      vtype_t *br = vcode_type_data(rhs_r->bounds);
15,756✔
4060

4061
      int64_t rbl = sadd64(bl->low, br->low);
15,756✔
4062
      int64_t rbh = sadd64(bl->high, br->high);
15,756✔
4063

4064
      vtype_repr_t repr = vtype_repr(lhs_r->type);
15,756✔
4065
      if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
15,756✔
4066
         op = VCODE_OP_ADD;   // Cannot overflow
776✔
4067
         locus = VCODE_INVALID_REG;
776✔
4068
      }
4069

4070
      vbounds = vtype_int(rbl, rbh);
15,756✔
4071
   }
4072

4073
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
16,043✔
4074

4075
   if (vbounds != VCODE_INVALID_TYPE)
16,043✔
4076
      vcode_reg_data(reg)->bounds = vbounds;
15,756✔
4077

4078
   return reg;
4079
}
4080

4081
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
40,420✔
4082
{
4083
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
40,420✔
4084
}
4085

4086
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
2,875✔
4087
{
4088
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
2,875✔
4089

4090
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
2,875✔
4091
                "trapping add may only be used with integer types");
4092

4093
   return result;
2,875✔
4094
}
4095

4096
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
39,118✔
4097
                               vcode_reg_t locus)
4098
{
4099
   int64_t lconst, rconst;
39,118✔
4100
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
39,118✔
4101
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
39,118✔
4102
   if (l_is_const && r_is_const)
39,118✔
4103
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
12,708✔
4104
   else if (r_is_const && rconst == 0)
26,410✔
4105
      return lhs;
4106
   else if (l_is_const && lconst == 0)
24,238✔
4107
      return emit_neg(rhs);
1,302✔
4108

4109
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
22,936✔
4110
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
22,936✔
4111
      reg_t *lhs_r = vcode_reg_data(lhs);
22,630✔
4112
      reg_t *rhs_r = vcode_reg_data(rhs);
22,630✔
4113

4114
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
22,630✔
4115
      vtype_t *br = vcode_type_data(rhs_r->bounds);
22,630✔
4116

4117
      int64_t rbl = ssub64(bl->low, br->high);
22,630✔
4118
      int64_t rbh = ssub64(bl->high, br->low);
22,630✔
4119

4120
      vtype_repr_t repr = vtype_repr(lhs_r->type);
22,630✔
4121
      if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
22,630✔
4122
         op = VCODE_OP_SUB;   // Cannot overflow
2,927✔
4123
         locus = VCODE_INVALID_REG;
2,927✔
4124
      }
4125

4126
      vbounds = vtype_int(rbl, rbh);
22,630✔
4127
   }
4128

4129
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
22,936✔
4130

4131
   if (vbounds != VCODE_INVALID_TYPE)
22,936✔
4132
      vcode_reg_data(reg)->bounds = vbounds;
22,630✔
4133

4134
   return reg;
4135
}
4136

4137
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
33,396✔
4138
{
4139
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
33,396✔
4140
}
4141

4142
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
5,722✔
4143
{
4144
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
5,722✔
4145

4146
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
5,722✔
4147
                "trapping sub may only be used with integer types");
4148

4149
   return result;
5,722✔
4150
}
4151

4152
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
62,054✔
4153
{
4154
   switch (vtype_kind(var->type)) {
62,054✔
4155
   case VCODE_TYPE_CARRAY:
12,337✔
4156
      op->type = vtype_pointer(vtype_elem(var->type));
12,337✔
4157
      op->result = vcode_add_reg(op->type);
12,337✔
4158
      vcode_reg_data(op->result)->bounds = vtype_bounds(var->type);
12,337✔
4159
      break;
12,337✔
4160

4161
   case VCODE_TYPE_RECORD:
6,337✔
4162
      op->type = vtype_pointer(var->type);
6,337✔
4163
      op->result = vcode_add_reg(op->type);
6,337✔
4164
      break;
6,337✔
4165

4166
   case VCODE_TYPE_INT:
43,380✔
4167
   case VCODE_TYPE_FILE:
4168
   case VCODE_TYPE_ACCESS:
4169
   case VCODE_TYPE_REAL:
4170
   case VCODE_TYPE_UARRAY:
4171
   case VCODE_TYPE_POINTER:
4172
   case VCODE_TYPE_SIGNAL:
4173
   case VCODE_TYPE_CONTEXT:
4174
   case VCODE_TYPE_OFFSET:
4175
   case VCODE_TYPE_TRIGGER:
4176
      op->type = vtype_pointer(var->type);
43,380✔
4177
      op->result = vcode_add_reg(op->type);
43,380✔
4178
      vcode_reg_data(op->result)->bounds = var->bounds;
43,380✔
4179
      break;
43,380✔
4180

4181
   default:
UNCOV
4182
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4183
                   istr(var->name));
4184
   }
4185
}
62,054✔
4186

4187
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
23,627✔
4188
{
4189
   // Try to find a previous index of this var by this offset
4190
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
784,891✔
4191
      if (other->address == var
50,813✔
4192
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
7,553✔
UNCOV
4193
              || (offset != VCODE_INVALID_REG
×
UNCOV
4194
                  && other->args.items[0] == offset)))
×
4195
         return other->result;
7,553✔
4196
   }
4197

4198
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
16,074✔
4199
   op->address = var;
16,074✔
4200

4201
   if (offset != VCODE_INVALID_REG)
16,074✔
UNCOV
4202
      vcode_add_arg(op, offset);
×
4203

4204
   vcode_calculate_var_index_type(op, vcode_var_data(var));
16,074✔
4205

4206
   if (offset != VCODE_INVALID_REG)
16,074✔
UNCOV
4207
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4208
                   "index offset r%d does not have offset type", offset);
4209

4210
   return op->result;
16,074✔
4211
}
4212

4213
vcode_reg_t emit_cast(vcode_type_t type, vcode_type_t bounds, vcode_reg_t reg)
206,174✔
4214
{
4215
   if (vtype_eq(vcode_reg_type(reg), type))
206,174✔
4216
      return reg;
206,174✔
4217

4218
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
77,292✔
4219
   vtype_kind_t to   = vtype_kind(type);
77,292✔
4220

4221
   const bool integral =
154,584✔
4222
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
77,292✔
4223
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
77,292✔
4224

4225
   int64_t value;
77,292✔
4226
   if (integral && vcode_reg_const(reg, &value))
77,292✔
4227
      return emit_const(type, value);
15,168✔
4228

4229
   // Try to find a previous cast of this register to this type
4230
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,219,784✔
4231
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
137,612✔
4232
         return other->result;
14,407✔
4233
   }
4234

4235
   op_t *op = vcode_add_op(VCODE_OP_CAST);
47,717✔
4236
   vcode_add_arg(op, reg);
47,717✔
4237
   op->type   = type;
47,717✔
4238
   op->result = vcode_add_reg(type);
47,717✔
4239

4240
   static const vcode_type_t allowed[][2] = {
47,717✔
4241
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4242
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4243
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4244
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4245
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4246
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4247
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4248
   };
4249

4250
   if (from == VCODE_TYPE_INT && bounds == VCODE_INVALID_TYPE) {
47,717✔
4251
      reg_t *rr = vcode_reg_data(op->result);
10,284✔
4252
      rr->bounds = vcode_reg_bounds(reg);
10,284✔
4253
   }
4254
   else if (to == VCODE_TYPE_INT && bounds != VCODE_INVALID_TYPE) {
37,433✔
4255
      reg_t *rr = vcode_reg_data(op->result);
31,077✔
4256
      rr->bounds = bounds;
31,077✔
4257
   }
4258

4259
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
87,163✔
4260
      if (from == allowed[i][0] && to == allowed[i][1])
87,163✔
4261
         return op->result;
4262
   }
4263

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

4267
void emit_return(vcode_reg_t reg)
53,450✔
4268
{
4269
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
53,450✔
4270
   if (reg != VCODE_INVALID_REG) {
53,450✔
4271
      vcode_add_arg(op, reg);
28,834✔
4272

4273
      const vtype_kind_t rkind = vcode_reg_kind(reg);
28,834✔
4274
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
28,834✔
4275
         vcode_heap_allocate(reg);
8,103✔
4276
         active_unit->flags |= UNIT_ESCAPING_TLAB;
8,103✔
4277
      }
4278

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

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

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

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

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

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

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

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

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

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

4357
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
36,843✔
4358
{
4359
   int64_t tconst;
36,843✔
4360
   if (vcode_reg_const(test, &tconst)) {
36,843✔
4361
      emit_jump(!!tconst ? btrue : bfalse);
4,845✔
4362
      return;
2,861✔
4363
   }
4364

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

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

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

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

4386
   return op->result;
7,487✔
4387
}
4388

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

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

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

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

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

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

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

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

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

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

4438
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
18,399✔
4439
                        vcode_reg_t rfalse)
4440
{
4441
   int64_t tconst;
18,399✔
4442
   if (vcode_reg_const(test, &tconst))
18,399✔
4443
      return !!tconst ? rtrue : rfalse;
4,408✔
4444
   else if (rtrue == rfalse)
13,991✔
4445
      return rtrue;
4446

4447
   // Find a previous identical select
4448
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
301,458✔
4449
      if (other->args.items[0] == test && other->args.items[1] == rtrue
12,463✔
4450
          && other->args.items[2] == rfalse)
690✔
4451
         return other->result;
629✔
4452
   }
4453

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

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

4465
   return op->result;
13,126✔
4466
}
4467

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

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

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

4522
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
6,629✔
4523

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

4528
   return result;
4529
}
4530

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

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

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

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

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

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

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

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

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

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

4577
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
45,848✔
4578
{
4579
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,533,743✔
4580
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
144,136✔
4581
         bool match = true;
4582
         for (int i = 0; match && i < ndims; i++) {
19,281✔
4583
            match = other->args.items[i*3 + 1] == dims[i].left
9,668✔
4584
               && other->args.items[i*3 + 2] == dims[i].right
8,201✔
4585
               && other->args.items[i*3 + 3] == dims[i].dir;
17,762✔
4586
         }
4587
         if (match)
9,613✔
4588
            return other->result;
8,039✔
4589
      }
4590
   }
4591

4592
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
37,809✔
4593
   vcode_add_arg(op, data);
37,809✔
4594
   for (int i = 0; i < ndims; i++) {
76,107✔
4595
      vcode_add_arg(op, dims[i].left);
38,298✔
4596
      vcode_add_arg(op, dims[i].right);
38,298✔
4597
      vcode_add_arg(op, dims[i].dir);
38,298✔
4598
   }
4599

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

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

4616
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
75,618✔
4617
      ? vtype_pointed(ptr_type) : ptr_type;
37,809✔
4618

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

4622
   return op->result;
37,809✔
4623
}
4624

4625
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
109,259✔
4626
                                  vcode_reg_t array, unsigned dim,
4627
                                  unsigned arg_index)
4628
{
4629
   // Reuse any previous operation in this block with the same arguments
4630
   VCODE_FOR_EACH_OP(other) {
1,183,247✔
4631
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,132,977✔
4632
          && (rtype == VCODE_INVALID_TYPE
23,056✔
4633
              || vtype_eq(rtype, vcode_reg_type(other->result))))
9,703✔
4634
         return other->result;
23,056✔
4635
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,109,921✔
4636
         return other->args.items[1 + (dim * 3) + arg_index];
35,933✔
4637
   }
4638

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

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

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

4650
   if (rtype == VCODE_INVALID_TYPE)
50,270✔
4651
      rtype = vtype_offset();
32,744✔
4652

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

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

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

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

4674
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
49,711✔
4675
{
4676
   VCODE_FOR_EACH_OP(other) {
518,547✔
4677
      if (other->kind == VCODE_OP_UARRAY_LEN) {
494,368✔
4678
         if (other->args.items[0] == array && other->dim == dim)
35,159✔
4679
            return other->result;
11,440✔
4680
      }
4681
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
459,209✔
4682
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
14,092✔
4683
                      "array dimension %d out of bounds", dim);
4684

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

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

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

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

4703
   return (op->result = vcode_add_reg(vtype_offset()));
24,179✔
4704
}
4705

4706
vcode_reg_t emit_unwrap(vcode_reg_t array)
38,020✔
4707
{
4708
   VCODE_FOR_EACH_OP(other) {
1,532,969✔
4709
      if (other->kind == VCODE_OP_WRAP && other->result == array)
1,505,834✔
4710
         return other->args.items[0];
9,471✔
4711
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
1,496,363✔
4712
         return other->result;
1,414✔
4713
   }
4714

4715
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
27,135✔
4716
   vcode_add_arg(op, array);
27,135✔
4717

4718
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
27,135✔
4719
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
27,135✔
4720
                "unwrap can only only be used with uarray types");
4721

4722
   vcode_type_t elem = vt->elem;
27,135✔
4723

4724
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
27,135✔
4725
      ? elem : vtype_pointer(elem);
27,135✔
4726

4727
   op->result = vcode_add_reg(rtype);
27,135✔
4728

4729
   reg_t *rr = vcode_reg_data(op->result);
27,135✔
4730
   rr->bounds = elem;
27,135✔
4731

4732
   return op->result;
27,135✔
4733
}
4734

4735
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
17,568✔
4736
                            vcode_reg_t dir)
4737
{
4738
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
545,075✔
UNCOV
4739
      if (other->args.items[0] == left
×
UNCOV
4740
          && other->args.items[1] == right
×
UNCOV
4741
          && other->args.items[2] == dir)
×
4742
         return other->result;
×
4743
   }
4744

4745
   int64_t dir_const;
17,568✔
4746
   if (vcode_reg_const(dir, &dir_const)) {
17,568✔
4747
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
12,911✔
4748
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
12,911✔
4749

4750
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
12,911✔
4751
         return emit_const(vtype_bool(), 1);
50✔
4752
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
12,861✔
4753
         return emit_const(vtype_bool(), 0);
6,222✔
4754
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
6,639✔
4755
         return emit_const(vtype_bool(), 1);
104✔
4756
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
6,535✔
4757
         return emit_const(vtype_bool(), 0);
1,702✔
4758
      else if (dir_const == RANGE_TO)
4,833✔
4759
         return emit_cmp(VCODE_CMP_GT, left, right);
1,503✔
4760
      else
4761
         return emit_cmp(VCODE_CMP_GT, right, left);
3,330✔
4762
   }
4763

4764
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
4,657✔
4765
   vcode_add_arg(op, left);
4,657✔
4766
   vcode_add_arg(op, right);
4,657✔
4767
   vcode_add_arg(op, dir);
4,657✔
4768

4769
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
4,657✔
4770
                "range left and right have different types");
4771
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
4,657✔
4772
                "dir argument to range length is not int");
4773

4774
   return (op->result = vcode_add_reg(vtype_bool()));
4,657✔
4775
}
4776

4777
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
14,127✔
4778
                              vcode_reg_t dir)
4779
{
4780
   vcode_reg_t left_array = VCODE_INVALID_REG,
14,127✔
4781
      right_array = VCODE_INVALID_REG,
14,127✔
4782
      dir_array = VCODE_INVALID_REG;
14,127✔
4783
   int left_dim = -1, right_dim = -1, dir_dim = -1;
14,127✔
4784

4785
   VCODE_FOR_EACH_OP(other) {
295,985✔
4786
      if (other->kind == VCODE_OP_RANGE_LENGTH
286,235✔
4787
          && other->args.items[0] == left
5,878✔
4788
          && other->args.items[1] == right
4,726✔
4789
          && other->args.items[2] == dir)
4,377✔
4790
         return other->result;
4,377✔
4791
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
281,858✔
4792
         left_array = other->args.items[0];
320✔
4793
         left_dim = other->dim;
320✔
4794
      }
4795
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
281,538✔
4796
         right_array = other->args.items[0];
320✔
4797
         right_dim = other->dim;
320✔
4798
      }
4799
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
281,218✔
4800
         dir_array = other->args.items[0];
1,054✔
4801
         dir_dim = other->dim;
1,054✔
4802
      }
4803
   }
4804

4805
   if (left_array != VCODE_INVALID_REG && left_array == right_array
9,750✔
4806
       && right_array == dir_array && left_dim == right_dim
320✔
4807
       && right_dim == dir_dim)
320✔
4808
      return emit_uarray_len(left_array, left_dim);
320✔
4809

4810
   int64_t lconst, rconst, dconst;
9,430✔
4811
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
9,430✔
4812
       && vcode_reg_const(right, &rconst)) {
5,261✔
4813

4814
      int64_t diff;
3,162✔
4815
      if (dconst == RANGE_TO)
3,162✔
4816
         diff = rconst - lconst;
2,839✔
4817
      else
4818
         diff = lconst - rconst;
323✔
4819

4820
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
3,162✔
4821
   }
4822

4823
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
6,268✔
4824
   vcode_add_arg(op, left);
6,268✔
4825
   vcode_add_arg(op, right);
6,268✔
4826
   vcode_add_arg(op, dir);
6,268✔
4827

4828
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
6,268✔
4829
                "range left and right have different types");
4830
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
6,268✔
4831
                "dir argument to range length is not int");
4832

4833
   return (op->result = vcode_add_reg(vtype_offset()));
6,268✔
4834
}
4835

4836
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
53,519✔
4837
{
4838
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
457,378✔
4839
      if (other->hops == hops && other->address == var)
61,834✔
4840
         return other->result;
7,539✔
4841
   }
4842

4843
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
45,980✔
4844
   op->hops    = hops;
45,980✔
4845
   op->address = var;
45,980✔
4846

4847
   VCODE_ASSERT(hops > 0, "invalid hop count");
45,980✔
4848

4849
   vcode_unit_t vu = active_unit;
45,980✔
4850
   for (int i = 0; i < hops; i++) {
102,685✔
4851
      vu = vu->context;
56,705✔
4852
      VCODE_ASSERT(vu, "hop count is greater than depth");
56,705✔
4853
   }
4854

4855
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
45,980✔
4856

4857
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
45,980✔
4858

4859
   return op->result;
45,980✔
4860
}
4861

4862
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
15,763✔
4863
                             vcode_reg_t size, vcode_reg_t value,
4864
                             vcode_reg_t flags, vcode_reg_t locus,
4865
                             vcode_reg_t offset)
4866
{
4867
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
15,763✔
4868
   vcode_add_arg(op, count);
15,763✔
4869
   vcode_add_arg(op, size);
15,763✔
4870
   vcode_add_arg(op, value);
15,763✔
4871
   vcode_add_arg(op, flags);
15,763✔
4872
   vcode_add_arg(op, locus);
15,763✔
4873
   if (offset != VCODE_INVALID_REG)
15,763✔
4874
      vcode_add_arg(op, offset);
5,550✔
4875

4876
   vcode_type_t vtype = vcode_reg_type(value);
15,763✔
4877
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
15,763✔
4878
   VCODE_ASSERT(vtype_eq(vtype, type)
15,763✔
4879
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4880
                "init signal value type does not match signal type");
4881
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
15,763✔
4882
                "locus argument to init signal must be a debug locus");
4883
   VCODE_ASSERT(offset == VCODE_INVALID_REG
15,763✔
4884
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4885
                "init signal offset argument must have pointer type");
4886

4887
   return (op->result = vcode_add_reg(vtype_signal(type)));
15,763✔
4888
}
4889

4890
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
3,325✔
4891
{
4892
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
3,325✔
4893
   vcode_add_arg(op, signal);
3,325✔
4894
   vcode_add_arg(op, resolution);
3,325✔
4895

4896
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
3,325✔
4897
                "signal argument has wrong type");
4898
   VCODE_ASSERT(vcode_reg_kind(resolution) == VCODE_TYPE_RESOLUTION,
3,325✔
4899
                "resolution wrapper argument has wrong type");
4900
}
3,325✔
4901

4902
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
75✔
4903
                                 vcode_reg_t size, vcode_reg_t locus,
4904
                                 vcode_reg_t kind, vcode_reg_t closure,
4905
                                 vcode_reg_t delay)
4906
{
4907
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
75✔
4908
   vcode_add_arg(op, count);
75✔
4909
   vcode_add_arg(op, size);
75✔
4910
   vcode_add_arg(op, locus);
75✔
4911
   vcode_add_arg(op, kind);
75✔
4912
   vcode_add_arg(op, closure);
75✔
4913
   vcode_add_arg(op, delay);
75✔
4914

4915
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
75✔
4916
                "count argument to implicit signal is not offset");
4917
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
75✔
4918
                "kind argument to implicit signal is not offset");
4919
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
75✔
4920
                "closure argument to implicit signal is not a closure");
4921
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
75✔
4922
                "locus argument to implicit signal must be a debug locus");
4923
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
75✔
4924
                "delay argument to implicit signal must be time");
4925

4926
   return (op->result = vcode_add_reg(vtype_signal(type)));
75✔
4927
}
4928

4929
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
5,296✔
4930
{
4931
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
5,296✔
4932
   vcode_add_arg(op, src);
5,296✔
4933
   vcode_add_arg(op, dst);
5,296✔
4934
   vcode_add_arg(op, count);
5,296✔
4935

4936
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
5,296✔
4937
                "src argument to map signal is not a signal");
4938
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
5,296✔
4939
                "dst argument to map signal is not a signal");
4940
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5,296✔
4941
                "count argument type to map signal is not offset");
4942
}
5,296✔
4943

4944
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
222✔
4945
{
4946
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
222✔
4947
   vcode_add_arg(op, src);
222✔
4948
   vcode_add_arg(op, dst);
222✔
4949
   vcode_add_arg(op, count);
222✔
4950

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

4957
void emit_map_implicit(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
57✔
4958
{
4959
   op_t *op = vcode_add_op(VCODE_OP_MAP_IMPLICIT);
57✔
4960
   vcode_add_arg(op, src);
57✔
4961
   vcode_add_arg(op, dst);
57✔
4962
   vcode_add_arg(op, count);
57✔
4963

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

4972
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
9,351✔
4973
{
4974
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
114,703✔
4975
      if (other->args.items[0] == target && other->args.items[1] == count)
13,832✔
4976
         return;
4977
   }
4978

4979
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
9,327✔
4980
   vcode_add_arg(op, target);
9,327✔
4981
   vcode_add_arg(op, count);
9,327✔
4982

4983
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
9,327✔
4984
                "target argument to drive signal is not a signal");
4985
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
9,327✔
4986
                "count argument type to drive signal is not offset");
4987
}
4988

4989
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
1,209✔
4990
                          vcode_reg_t count, vcode_reg_t reject,
4991
                          vcode_reg_t after)
4992
{
4993
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
1,209✔
4994
   vcode_add_arg(op, target);
1,209✔
4995
   vcode_add_arg(op, source);
1,209✔
4996
   vcode_add_arg(op, count);
1,209✔
4997
   vcode_add_arg(op, reject);
1,209✔
4998
   vcode_add_arg(op, after);
1,209✔
4999

5000
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
1,209✔
5001
                "target argument to transfer signal is not a signal");
5002
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
1,209✔
5003
                "count argument type to transfer signal is not offset");
5004
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
1,209✔
5005
                "source argument to transfer signal is not a signal");
5006
}
1,209✔
5007

5008
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
3,211✔
5009
                                    vcode_reg_t ileft, vcode_reg_t nlits)
5010
{
5011
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
133,953✔
5012
      if (other->args.items[0] == closure
2,255✔
5013
          && other->args.items[1] == ileft
2,252✔
5014
          && other->args.items[2] == nlits)
2,252✔
5015
         return other->result;
2,252✔
5016
   }
5017

5018
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
959✔
5019
                "first argument to resolution wrapper must be closure");
5020

5021
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
959✔
5022
   vcode_add_arg(op, closure);
959✔
5023
   vcode_add_arg(op, ileft);
959✔
5024
   vcode_add_arg(op, nlits);
959✔
5025

5026
   return (op->result = vcode_add_reg(vtype_resolution(type)));
959✔
5027
}
5028

5029
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t atype,
3,574✔
5030
                         vcode_type_t rtype)
5031
{
5032
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
139,962✔
5033
      if (other->func == func && other->args.items[0] == context)
2,690✔
5034
         return other->result;
2,252✔
5035
   }
5036

5037
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
1,322✔
5038
   vcode_add_arg(op, context);
1,322✔
5039
   op->func = func;
1,322✔
5040
   op->type = atype;
1,322✔
5041

5042
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
1,322✔
5043
                "invalid closure context argument");
5044

5045
   return (op->result = vcode_add_reg(vtype_closure(rtype)));
1,322✔
5046
}
5047

5048
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
30,604✔
5049
{
5050
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
46,744✔
5051
      if (other->func == name)
23,195✔
5052
         return other->result;
12,840✔
5053
   }
5054

5055
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
17,764✔
5056
   op->func = name;
17,764✔
5057
   if (context != VCODE_INVALID_REG)
17,764✔
5058
      vcode_add_arg(op, context);
182✔
5059

5060
   VCODE_ASSERT(context == VCODE_INVALID_REG
17,764✔
5061
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5062
                "invalid protected init context argument");
5063
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
17,764✔
5064
                || active_unit->kind == VCODE_UNIT_PACKAGE
5065
                || active_unit->kind == VCODE_UNIT_THUNK,
5066
                "cannot use package init here");
5067
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
17,764✔
5068

5069
   return (op->result = vcode_add_reg(vtype_context(name)));
17,764✔
5070
}
5071

5072
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
163✔
5073
                                vcode_reg_t path_name, vcode_reg_t inst_name)
5074
{
5075
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
163✔
5076
   vcode_add_arg(op, context);
163✔
5077
   op->func = vtype_name(type);
163✔
5078

5079
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
163✔
5080
      vcode_add_arg(op, path_name);
38✔
5081
      vcode_add_arg(op, inst_name);
38✔
5082

5083
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
38✔
5084
                   "path name argument must be uarray");
5085
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
38✔
5086
                   "inst name argument must be uarray");
5087
   }
5088

5089
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
163✔
5090
                "protected init type must be context");
5091
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
163✔
5092
                "invalid protected init context argument");
5093

5094
   return (op->result = vcode_add_reg(type));
163✔
5095
}
5096

5097
void emit_process_init(ident_t name, vcode_reg_t locus)
103✔
5098
{
5099
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
103✔
5100
   vcode_add_arg(op, locus);
103✔
5101
   op->func = name;
103✔
5102

5103
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
103✔
5104
                "locus argument to process init must be a debug locus");
5105
}
103✔
5106

5107
void emit_protected_free(vcode_reg_t obj)
7✔
5108
{
5109
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
7✔
5110
   vcode_add_arg(op, obj);
7✔
5111

5112
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
7✔
5113
                "protected object type must be context");
5114
}
7✔
5115

5116
vcode_reg_t emit_context_upref(int hops)
15,646✔
5117
{
5118
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
107,730✔
5119
      if (other->hops == hops)
7,005✔
5120
         return other->result;
6,949✔
5121
   }
5122

5123
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
8,697✔
5124
   op->hops = hops;
8,697✔
5125

5126
   VCODE_ASSERT(hops >= 0, "invalid hop count");
8,697✔
5127

5128
   vcode_unit_t vu = active_unit;
8,697✔
5129
   for (int i = 0; i < hops; i++) {
16,656✔
5130
      vu = vu->context;
7,959✔
5131
      VCODE_ASSERT(vu, "hop count is greater than depth");
7,959✔
5132
   }
5133

5134
   return (op->result = vcode_add_reg(vtype_context(vu->name)));
8,697✔
5135
}
5136

5137
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
649✔
5138
                                    vcode_reg_t len)
5139
{
5140
   op_t *op = vcode_add_op(opkind);
649✔
5141
   vcode_add_arg(op, nets);
649✔
5142
   vcode_add_arg(op, len);
649✔
5143

5144
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
649✔
5145
                "argument to %s is not a signal", vcode_op_string(opkind));
5146

5147
   return (op->result = vcode_add_reg(vtype_bool()));
649✔
5148
}
5149

5150
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
429✔
5151
{
5152
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
429✔
5153
}
5154

5155
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
220✔
5156
{
5157
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
220✔
5158
}
5159

5160
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
41,226✔
5161
{
5162
   // Try scanning backwards through the block for another record ref
5163
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
2,762,253✔
5164
      if (other->args.items[0] == record && other->field == field)
515,591✔
5165
         return other->result;
3,851✔
5166
   }
5167

5168
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
37,375✔
5169
   op->field = field;
37,375✔
5170
   vcode_add_arg(op, record);
37,375✔
5171

5172
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
37,375✔
5173

5174
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
37,375✔
5175
                "argument to record ref must be a pointer");
5176

5177
   vtype_t *rtype = vcode_type_data(rptype->pointed);
37,375✔
5178
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
37,375✔
5179
                "argument must be pointer to record or record signal");
5180

5181
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
37,375✔
5182

5183
   vcode_type_t field_type  = rtype->fields.items[field];
37,375✔
5184
   vcode_type_t bounds_type = field_type;
37,375✔
5185
   vcode_type_t result_type = field_type;
37,375✔
5186

5187
   const vtype_kind_t fkind = vtype_kind(field_type);
37,375✔
5188
   if (fkind == VCODE_TYPE_CARRAY)
37,375✔
5189
      result_type = bounds_type = vtype_elem(field_type);
5,126✔
5190
   else if (fkind == VCODE_TYPE_UARRAY) {
32,249✔
5191
      bounds_type = vtype_elem(field_type);
2,678✔
5192
      result_type = field_type;
2,678✔
5193
   }
5194

5195
   op->result = vcode_add_reg(vtype_pointer(result_type));
37,375✔
5196

5197
   reg_t *rr = vcode_reg_data(op->result);
37,375✔
5198
   rr->bounds = bounds_type;
37,375✔
5199

5200
   return op->result;
37,375✔
5201
}
5202

5203
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
35,635✔
5204
{
5205
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
1,664,642✔
5206
      if (other->args.items[0] == array && other->args.items[1] == offset)
98,409✔
5207
         return other->result;
1,177✔
5208
   }
5209

5210
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
34,458✔
5211
   vcode_add_arg(op, array);
34,458✔
5212
   vcode_add_arg(op, offset);
34,458✔
5213

5214
   vcode_type_t rtype = vcode_reg_type(array);
34,458✔
5215
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
34,458✔
5216
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5217
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5218
                "argument to array ref must be a pointer or signal");
5219
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
34,458✔
5220
                "array ref offset argument must have offset type");
5221

5222
   op->result = vcode_add_reg(rtype);
34,458✔
5223

5224
   reg_t *rr = vcode_reg_data(op->result);
34,458✔
5225
   rr->bounds = vcode_reg_bounds(array);
34,458✔
5226

5227
   return op->result;
34,458✔
5228
}
5229

5230
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
20,919✔
5231
{
5232
   int64_t cconst;
20,919✔
5233
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
20,919✔
5234
       && cconst == 0)
10,642✔
5235
      return;
4,935✔
5236
   else if (dest == src)
20,759✔
5237
      return;
5238

5239
   op_t *op = vcode_add_op(VCODE_OP_COPY);
15,984✔
5240
   vcode_add_arg(op, dest);
15,984✔
5241
   vcode_add_arg(op, src);
15,984✔
5242
   if (count != VCODE_INVALID_REG)
15,984✔
5243
      vcode_add_arg(op, count);
14,163✔
5244

5245
   vcode_type_t dtype = vcode_reg_type(dest);
15,984✔
5246
   vcode_type_t stype = vcode_reg_type(src);
15,984✔
5247

5248
   vtype_kind_t dkind = vtype_kind(dtype);
15,984✔
5249
   vtype_kind_t skind = vtype_kind(stype);
15,984✔
5250

5251
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
15,984✔
5252
                "destination type is not a pointer or access");
5253
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
15,984✔
5254
                "source type is not a pointer or access");
5255
   VCODE_ASSERT(vtype_eq(dtype, stype),
15,984✔
5256
                "source and destination types do not match");
5257
   VCODE_ASSERT(count == VCODE_INVALID_REG
15,984✔
5258
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5259
                "count is not offset type");
5260

5261
   op->type = vtype_pointed(dtype);
15,984✔
5262
}
5263

5264
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
5,904✔
5265
{
5266
   VCODE_FOR_EACH_OP(other) {
98,412✔
5267
      if (other->kind == VCODE_OP_CLEAR_EVENT)
92,544✔
5268
         break;
5269
      else if (other->kind == VCODE_OP_SCHED_EVENT
92,514✔
5270
               && other->args.items[0] == nets
4,774✔
5271
               && other->args.items[1] == n_elems)
9✔
5272
         return;
5273
   }
5274

5275
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
5,898✔
5276
   vcode_add_arg(op, nets);
5,898✔
5277
   vcode_add_arg(op, n_elems);
5,898✔
5278

5279
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
5,898✔
5280
                "nets argument to sched event must be signal");
5281
}
5282

5283
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
507✔
5284
{
5285
   VCODE_FOR_EACH_OP(other) {
2,340✔
5286
      if (other->kind == VCODE_OP_SCHED_EVENT)
1,833✔
5287
         break;
5288
      else if (other->kind == VCODE_OP_CLEAR_EVENT
1,833✔
5289
               && other->args.items[0] == nets
39✔
UNCOV
5290
               && other->args.items[1] == n_elems)
×
5291
         return;
5292
   }
5293

5294
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
507✔
5295
   vcode_add_arg(op, nets);
507✔
5296
   vcode_add_arg(op, n_elems);
507✔
5297

5298
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
507✔
5299
                "nets argument to clear event must be signal");
5300
}
5301

5302
void emit_resume(ident_t func)
880✔
5303
{
5304
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
880✔
5305
   op->func = func;
880✔
5306

5307
   block_t *b = &(active_unit->blocks.items[active_block]);
880✔
5308
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
880✔
5309
}
880✔
5310

5311
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
5,684✔
5312
{
5313
   int64_t lconst;
5,684✔
5314
   if (vcode_reg_const(len, &lconst) && lconst == 0)
5,684✔
5315
      return;
29✔
5316

5317
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
5,655✔
5318
   vcode_add_arg(op, ptr);
5,655✔
5319
   vcode_add_arg(op, value);
5,655✔
5320
   vcode_add_arg(op, len);
5,655✔
5321

5322
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
5,655✔
5323
                "target of memset must have pointer type");
5324
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
5,655✔
5325
                "value of memset must have scalar type");
5326
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
5,655✔
5327
                "length of memset must have offset type");
5328
}
5329

5330
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
641✔
5331
               const vcode_block_t *blocks, int ncases)
5332
{
5333
   int64_t cval1, cval2;
641✔
5334
   bool is_const = vcode_reg_const(value, &cval1);
641✔
5335

5336
   for (int i = 0; i < ncases; i++) {
5,350✔
5337
      bool can_fold = false;
4,713✔
5338
      if (cases[i] == value)
4,713✔
5339
         can_fold = true;
5340
      else if (is_const && vcode_reg_const(cases[i], &cval2))
4,713✔
5341
         can_fold = (cval1 == cval2);
4✔
5342

5343
      if (can_fold) {
4✔
5344
         emit_jump(blocks[i]);
4✔
5345
         return;
8✔
5346
      }
5347
   }
5348

5349
   if (is_const) {
637✔
UNCOV
5350
      emit_jump(def);
×
UNCOV
5351
      return;
×
5352
   }
5353

5354
   op_t *op = vcode_add_op(VCODE_OP_CASE);
637✔
5355
   vcode_add_arg(op, value);
637✔
5356
   vcode_add_target(op, def);
637✔
5357

5358
   for (int i = 0; i < ncases; i++) {
5,346✔
5359
      vcode_add_arg(op, cases[i]);
4,709✔
5360
      vcode_add_target(op, blocks[i]);
4,709✔
5361

5362
#ifdef DEBUG
5363
      for (int j = 0; j < i; j++)
245,202✔
5364
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
240,493✔
5365
#endif
5366
   }
5367
}
5368

5369
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
254✔
5370
                    vcode_reg_t kind, vcode_reg_t status)
5371
{
5372
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
254✔
5373
   vcode_add_arg(op, file);
254✔
5374
   vcode_add_arg(op, name);
254✔
5375
   vcode_add_arg(op, length);
254✔
5376
   vcode_add_arg(op, kind);
254✔
5377
   if (status != VCODE_INVALID_REG)
254✔
5378
      vcode_add_arg(op, status);
26✔
5379

5380
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
254✔
5381
                "file open first argument must have file pointer type");
5382
}
254✔
5383

5384
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
125✔
5385
{
5386
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
125✔
5387
   vcode_add_arg(op, file);
125✔
5388
   vcode_add_arg(op, value);
125✔
5389
   if (length != VCODE_INVALID_REG)
125✔
5390
      vcode_add_arg(op, length);
68✔
5391

5392
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
125✔
5393
                "file write first argument must have file pointer type");
5394
}
125✔
5395

5396
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
75✔
5397
                    vcode_reg_t inlen, vcode_reg_t outlen)
5398
{
5399
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
75✔
5400
   vcode_add_arg(op, file);
75✔
5401
   vcode_add_arg(op, ptr);
75✔
5402
   if (inlen != VCODE_INVALID_REG) {
75✔
5403
      vcode_add_arg(op, inlen);
27✔
5404
      if (outlen != VCODE_INVALID_REG)
27✔
5405
         vcode_add_arg(op, outlen);
18✔
5406
   }
5407

5408
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
75✔
5409
                "file read first argument must have file pointer type");
5410
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
75✔
5411
                "file read pointer argument must have pointer type");
5412
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
75✔
5413
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5414
                "file read outlen argument must have pointer type");
5415
}
75✔
5416

5417
vcode_reg_t emit_null(vcode_type_t type)
9,374✔
5418
{
5419
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
217,837✔
5420
      if (vtype_eq(vcode_reg_type(other->result), type))
4,754✔
5421
         return other->result;
2,361✔
5422
   }
5423

5424
   op_t *op = vcode_add_op(VCODE_OP_NULL);
7,013✔
5425
   op->result = vcode_add_reg(type);
7,013✔
5426

5427
   vtype_kind_t kind = vtype_kind(type);
7,013✔
5428
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
7,013✔
5429
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5430
                "null type must be file, access, context, or pointer");
5431

5432
   return op->result;
5433
}
5434

5435
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
428✔
5436
{
5437
   op_t *op = vcode_add_op(VCODE_OP_NEW);
428✔
5438
   if (length != VCODE_INVALID_REG)
428✔
5439
      vcode_add_arg(op, length);
337✔
5440

5441
   op->result = vcode_add_reg(vtype_access(type));
428✔
5442

5443
   vtype_kind_t kind = vtype_kind(type);
428✔
5444
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
428✔
5445
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5446
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5447
                "new type must be int, real, record, access, or uarray");
5448
   VCODE_ASSERT(length == VCODE_INVALID_REG
428✔
5449
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5450
                "new length must have offset type");
5451

5452
   return op->result;
428✔
5453
}
5454

5455
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
1,755✔
5456
{
5457
   VCODE_FOR_EACH_OP(other) {
104,961✔
5458
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
103,838✔
5459
         return;
5460
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
103,461✔
5461
         return;
5462
   }
5463

5464
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
1,123✔
5465
   vcode_add_arg(op, ptr);
1,123✔
5466
   vcode_add_arg(op, locus);
1,123✔
5467

5468
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
1,123✔
5469
                "null check argument must be an access");
5470
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,123✔
5471
                "locus argument to null check must be a debug locus");
5472
}
5473

5474
void emit_deallocate(vcode_reg_t ptr)
207✔
5475
{
5476
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
207✔
5477
   vcode_add_arg(op, ptr);
207✔
5478

5479
   vcode_type_t ptype = vcode_reg_type(ptr);
207✔
5480
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
207✔
5481
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5482
                "deallocate argument must be pointer to access");
5483
}
207✔
5484

5485
vcode_reg_t emit_all(vcode_reg_t reg)
2,183✔
5486
{
5487
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
146,087✔
5488
      if (other->args.items[0] == reg)
9,251✔
5489
         return other->result;
632✔
5490
   }
5491

5492
   op_t *op = vcode_add_op(VCODE_OP_ALL);
1,551✔
5493
   vcode_add_arg(op, reg);
1,551✔
5494

5495
   vcode_type_t vtype = vcode_reg_type(reg);
1,551✔
5496

5497
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
1,551✔
5498
                "all argument must be an access");
5499

5500
   vcode_type_t pointed = vtype_pointed(vtype);
1,551✔
5501
   op->result = vcode_add_reg(vtype_pointer(pointed));
1,551✔
5502

5503
   reg_t *rr = vcode_reg_data(op->result);
1,551✔
5504
   rr->bounds = pointed;
1,551✔
5505

5506
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
1,551✔
5507
                "cannot dereference opaque type");
5508

5509
   return op->result;
5510
}
5511

5512
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
14,854✔
5513
{
5514
   block_t *b = &(active_unit->blocks.items[active_block]);
14,854✔
5515
   for (int i = b->ops.count - 1; i >= 0; i--) {
364,560✔
5516
      const op_t *other = &(b->ops.items[i]);
350,261✔
5517
      if (other->kind == kind && other->args.items[0] == sig)
350,261✔
5518
         return other->result;
555✔
5519
   }
5520

5521
   op_t *op = vcode_add_op(kind);
14,299✔
5522
   vcode_add_arg(op, sig);
14,299✔
5523

5524
   vcode_type_t stype = vcode_reg_type(sig);
14,299✔
5525
   op->type = stype;
14,299✔
5526

5527
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
14,299✔
5528
                "argument r%d to resolved is not a signal", sig);
5529

5530
   vcode_type_t rtype = vtype_base(stype);
14,299✔
5531

5532
   const vtype_kind_t rkind = vtype_kind(rtype);
14,299✔
5533
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
14,299✔
UNCOV
5534
      rtype = vtype_elem(rtype);
×
5535

5536
   VCODE_ASSERT(vtype_is_scalar(rtype),
14,299✔
5537
                "resolved signal base type must be scalar");
5538

5539
   op->result = vcode_add_reg(vtype_pointer(rtype));
14,299✔
5540

5541
   reg_t *rr = vcode_reg_data(op->result);
14,299✔
5542
   rr->bounds = rtype;
14,299✔
5543

5544
   return op->result;
14,299✔
5545
}
5546

5547
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
14,759✔
5548
{
5549
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
14,759✔
5550
}
5551

5552
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
95✔
5553
{
5554
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
95✔
5555
}
5556

5557
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
21✔
5558
{
5559
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
21✔
5560
   vcode_add_arg(op, signal);
21✔
5561
   if (len != VCODE_INVALID_REG)
21✔
5562
      vcode_add_arg(op, len);
9✔
5563

5564
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
21✔
5565
                "signal argument to last event must have signal type");
5566
   VCODE_ASSERT(len == VCODE_INVALID_REG
21✔
5567
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5568
                "length argument to last event must have offset type");
5569

5570
   return (op->result = vcode_add_reg(vtype_time()));
21✔
5571
}
5572

5573
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
27✔
5574
{
5575
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
27✔
5576
   vcode_add_arg(op, signal);
27✔
5577
   if (len != VCODE_INVALID_REG)
27✔
5578
      vcode_add_arg(op, len);
6✔
5579

5580
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
27✔
5581
                "signal argument to last active must have signal type");
5582
   VCODE_ASSERT(len == VCODE_INVALID_REG
27✔
5583
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5584
                "length argument to last active must have offset type");
5585

5586
   return (op->result = vcode_add_reg(vtype_time()));
27✔
5587
}
5588

5589
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,202✔
5590
{
5591
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,202✔
5592
   vcode_add_arg(op, signal);
4,202✔
5593
   vcode_add_arg(op, locus);
4,202✔
5594

5595
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,202✔
5596
                "signal argument must have signal type");
5597
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
4,202✔
5598
                "locus argument must have debug locus type");
5599
}
4,202✔
5600

5601
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
36✔
5602
{
5603
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
36✔
5604
   vcode_add_arg(op, signal);
36✔
5605
   vcode_add_arg(op, len);
36✔
5606

5607
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5608
                "signal argument to last active must have signal type");
5609
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
36✔
5610
                "length argument to last active must have offset type");
5611

5612
   return (op->result = vcode_add_reg(vtype_bool()));
36✔
5613
}
5614

5615
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
137✔
5616
{
5617
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
137✔
5618
   vcode_add_arg(op, signal);
137✔
5619
   if (len != VCODE_INVALID_REG)
137✔
5620
      vcode_add_arg(op, len);
30✔
5621

5622
   vcode_type_t signal_type = vcode_reg_type(signal);
137✔
5623

5624
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
137✔
5625
                "signal argument to last active must have signal type");
5626
   VCODE_ASSERT(len == VCODE_INVALID_REG
137✔
5627
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5628
                "length argument to last active must have offset type");
5629

5630
   vcode_type_t base_type = vtype_base(signal_type);
137✔
5631
   op->result = vcode_add_reg(vtype_pointer(base_type));
137✔
5632

5633
   reg_t *rr = vcode_reg_data(op->result);
137✔
5634
   rr->bounds = base_type;
137✔
5635

5636
   return op->result;
137✔
5637
}
5638

5639
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
21,908✔
5640
                       vcode_reg_t dim)
5641
{
5642
   if (rlen == llen)
21,908✔
5643
      return;
5644

5645
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
185,535✔
5646
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
2,845✔
5647
         return;
5648
   }
5649

5650
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
6,787✔
5651
   vcode_add_arg(op, llen);
6,787✔
5652
   vcode_add_arg(op, rlen);
6,787✔
5653
   vcode_add_arg(op, locus);
6,787✔
5654
   if (dim != VCODE_INVALID_REG)
6,787✔
5655
      vcode_add_arg(op, dim);
24✔
5656

5657
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6,787✔
5658
                "locus argument to length check must be a debug locus");
5659
}
5660

5661
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
816✔
5662
{
5663
   int64_t cval;
816✔
5664
   if (vcode_reg_const(exp, &cval) && cval >= 0)
816✔
5665
      return;
299✔
5666

5667
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
3,254✔
5668
      if (other->args.items[0] == exp)
12✔
5669
         return;
5670
   }
5671

5672
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
517✔
5673
   vcode_add_arg(op, exp);
517✔
5674
   vcode_add_arg(op, locus);
517✔
5675

5676
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
517✔
5677
                "exp argument to exponent check must be a integer");
5678
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
517✔
5679
                "locus argument to exponent check must be a debug locus");
5680
}
5681

5682
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
1,081✔
5683
{
5684
   int64_t cval;
1,081✔
5685
   if (vcode_reg_const(denom, &cval) && cval != 0)
1,081✔
5686
      return;
978✔
5687

5688
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
2,886✔
5689
      if (other->args.items[0] == denom)
56✔
5690
         return;
5691
   }
5692

5693
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
103✔
5694
   vcode_add_arg(op, denom);
103✔
5695
   vcode_add_arg(op, locus);
103✔
5696

5697
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
103✔
5698
                "denom argument to zero check must be a integer");
5699
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
103✔
5700
                "locus argument to zero check must be a debug locus");
5701
}
5702

5703
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
48,781✔
5704
                                   vcode_reg_t right, vcode_reg_t dir)
5705
{
5706
   int64_t dconst;
48,781✔
5707
   if (vcode_reg_const(dir, &dconst)) {
48,781✔
5708
      int64_t lconst, rconst;
39,844✔
5709
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
39,844✔
5710
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
29,949✔
5711
            || (dconst == RANGE_DOWNTO && rconst > lconst);
63,313✔
5712

5713
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
33,365✔
5714

5715
         const bool ok_static =
66,730✔
5716
            (dconst == RANGE_TO
5717
             && bounds->low >= lconst && bounds->high <= rconst)
29,949✔
5718
            || (dconst == RANGE_DOWNTO
7,944✔
5719
                && bounds->low >= rconst && bounds->high <= lconst)
3,416✔
5720
            || (!is_null && (reg == left || reg == right));
38,103✔
5721

5722
         return ok_static;
39,046✔
5723
      }
5724
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
6,479✔
5725
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
6,087✔
5726
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
6,087✔
5727

5728
         assert(lbounds->kind == VCODE_TYPE_REAL);
6,087✔
5729
         assert(rbounds->kind == VCODE_TYPE_REAL);
6,087✔
5730

5731
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
6,087✔
5732
         assert(bounds->kind == VCODE_TYPE_REAL);
6,087✔
5733

5734
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
6,087✔
5735
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
5,681✔
5736
            // Covers the complete double range so can never overflow
5737
            return true;
5738
         }
5739
      }
5740
   }
5741

5742
   return false;
5743
}
5744

5745
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
49,354✔
5746
                              vcode_reg_t left, vcode_reg_t right,
5747
                              vcode_reg_t dir, vcode_reg_t locus,
5748
                              vcode_reg_t hint)
5749
{
5750
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
2,336,932✔
5751
      if (other->args.items[0] == reg && other->args.items[1] == left
13,464✔
5752
          && other->args.items[2] == right && other->args.items[3] == dir)
579✔
5753
         return;
5754
   }
5755

5756
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
48,781✔
5757
      emit_comment("Elided bounds check for r%d", reg);
34,308✔
5758
      return;
34,308✔
5759
   }
5760

5761
   op_t *op = vcode_add_op(kind);
14,473✔
5762
   vcode_add_arg(op, reg);
14,473✔
5763
   vcode_add_arg(op, left);
14,473✔
5764
   vcode_add_arg(op, right);
14,473✔
5765
   vcode_add_arg(op, dir);
14,473✔
5766
   vcode_add_arg(op, locus);
14,473✔
5767
   vcode_add_arg(op, hint);
14,473✔
5768

5769
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
14,473✔
5770
                "locus argument to bounds check must be a debug locus");
5771
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
14,473✔
5772
                "hint argument to bounds check must be a debug locus");
5773
}
5774

5775
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
8,852✔
5776
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5777
{
5778
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
8,852✔
5779
}
8,852✔
5780

5781
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
40,502✔
5782
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5783
{
5784
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
40,502✔
5785
}
40,502✔
5786

5787
void emit_package_scope(vcode_reg_t locus)
45✔
5788
{
5789
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
45✔
5790
   vcode_add_arg(op, locus);
45✔
5791

5792
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5793
                "locus argument to package scope must be a debug locus");
5794
}
45✔
5795

5796
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
626✔
5797
{
5798
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
626✔
5799
   vcode_add_arg(op, locus);
626✔
5800
   op->type = type;
626✔
5801

5802
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
626✔
5803
                "locus argument to array scope must be a debug locus");
5804
}
626✔
5805

5806
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
1,569✔
5807
{
5808
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
1,569✔
5809
   vcode_add_arg(op, locus);
1,569✔
5810
   op->type = type;
1,569✔
5811

5812
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,569✔
5813
                "locus argument to record scope must be a debug locus");
5814
}
1,569✔
5815

5816
void emit_pop_scope(void)
2,240✔
5817
{
5818
   vcode_add_op(VCODE_OP_POP_SCOPE);
2,240✔
5819
}
2,240✔
5820

5821
vcode_reg_t emit_debug_locus(object_t *obj)
120,223✔
5822
{
5823
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
6,450,757✔
5824
      if (other->object == obj)
979,767✔
5825
         return other->result;
10,096✔
5826
   }
5827

5828
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
110,127✔
5829
   op->object = obj;
110,127✔
5830

5831
   return (op->result = vcode_add_reg(vtype_debug_locus()));
110,127✔
5832
}
5833

UNCOV
5834
void emit_debug_out(vcode_reg_t reg)
×
5835
{
5836
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
UNCOV
5837
   vcode_add_arg(op, reg);
×
5838
}
×
5839

5840
void emit_cover_stmt(uint32_t tag)
1,006✔
5841
{
5842
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,006✔
5843
   op->tag = tag;
1,006✔
5844
}
1,006✔
5845

5846
void emit_cover_branch(uint32_t tag)
495✔
5847
{
5848
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
495✔
5849
   op->tag = tag;
495✔
5850
}
495✔
5851

5852
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
313✔
5853
{
5854
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
313✔
5855
   vcode_add_arg(op, signal);
313✔
5856
   op->tag = tag;
313✔
5857
}
313✔
5858

5859
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
12✔
5860
{
5861
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
12✔
5862
   vcode_add_arg(op, signal);
12✔
5863
   vcode_add_arg(op, low);
12✔
5864
   op->tag = tag;
12✔
5865
}
12✔
5866

5867
void emit_cover_expr(uint32_t tag)
856✔
5868
{
5869
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
856✔
5870
   op->tag = tag;
856✔
5871
}
856✔
5872

5873
void emit_unreachable(vcode_reg_t locus)
610✔
5874
{
5875
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
610✔
5876
   if (locus != VCODE_INVALID_REG)
610✔
5877
      vcode_add_arg(op, locus);
137✔
5878
}
610✔
5879

5880
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
1,449✔
5881
{
5882
   active_unit->flags |= UNIT_UNDEFINED;
1,449✔
5883

5884
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
1,449✔
5885
   op->result = vcode_add_reg(type);
1,449✔
5886
   vcode_reg_data(op->result)->bounds = bounds;
1,449✔
5887

5888
   return op->result;
1,449✔
5889
}
5890

5891
void emit_debug_info(const loc_t *loc)
1,364,381✔
5892
{
5893
   if (!loc_invalid_p(loc))
1,364,381✔
5894
      vcode_block_data()->last_loc = *loc;
1,336,951✔
5895
}
1,364,381✔
5896

5897
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
4,144✔
5898
{
5899
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
155,054✔
5900
      if (other->args.items[0] == context && other->ident == name)
8,855✔
5901
         return other->result;
1,631✔
5902
   }
5903

5904
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
2,513✔
5905
   vcode_add_arg(op, context);
2,513✔
5906
   op->ident = name;
2,513✔
5907

5908
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
2,513✔
5909
                "first argument to link var must be context");
5910

5911
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
2,513✔
5912
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
79✔
5913
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
79✔
5914
   }
5915
   else {
5916
      op->result = vcode_add_reg(vtype_pointer(type));
2,434✔
5917
      vcode_reg_data(op->result)->bounds = type;
2,434✔
5918
   }
5919

5920
   return op->result;
2,513✔
5921
}
5922

5923
vcode_reg_t emit_link_package(ident_t name)
24,866✔
5924
{
5925
   VCODE_FOR_EACH_OP(other) {
1,119,122✔
5926
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
1,107,605✔
5927
         return other->result;
8,007✔
5928
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
1,099,598✔
5929
         return other->result;
5,342✔
5930
   }
5931

5932
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
11,517✔
5933
   op->ident = name;
11,517✔
5934

5935
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
11,517✔
5936

5937
   return (op->result = vcode_add_reg(vtype_context(name)));
11,517✔
5938
}
5939

5940
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
765✔
5941
{
5942
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
1,827✔
UNCOV
5943
      if (other->args.items[0] == state)
×
5944
         return;
5945
   }
5946

5947
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
765✔
5948
   vcode_add_arg(op, state);
765✔
5949
   if (strong != VCODE_INVALID_REG)
765✔
5950
      vcode_add_arg(op, strong);
18✔
5951

5952
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
765✔
5953
                "state must have integer type");
5954
   VCODE_ASSERT(strong == VCODE_INVALID_REG
765✔
5955
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
5956
                "strong argument not is not boolean");
5957
}
5958

5959
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
45✔
5960
                               vcode_reg_t locus, vcode_reg_t bounds)
5961
{
5962
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
45✔
5963
   vcode_add_arg(op, value);
45✔
5964
   vcode_add_arg(op, context);
45✔
5965
   vcode_add_arg(op, locus);
45✔
5966
   if (bounds != VCODE_INVALID_REG)
45✔
5967
      vcode_add_arg(op, bounds);
6✔
5968

5969
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
45✔
5970
                "invalid reflect value context argument");
5971
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5972
                "locus argument to reflect value must be a debug locus");
5973

5974
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
45✔
5975
}
5976

5977
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
42✔
5978
                                 vcode_reg_t bounds)
5979
{
5980
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
5981
   vcode_add_arg(op, context);
42✔
5982
   vcode_add_arg(op, locus);
42✔
5983
   if (bounds != VCODE_INVALID_REG)
42✔
UNCOV
5984
      vcode_add_arg(op, bounds);
×
5985

5986
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
5987
                "invalid reflect value context argument");
5988
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
5989
                "locus argument to reflect value must be a debug locus");
5990

5991
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
42✔
5992
}
5993

5994
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
217✔
5995
                                  int nargs)
5996
{
5997
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
217✔
5998
   op->func = func;
217✔
5999

6000
   for (int i = 0; i < nargs; i++)
579✔
6001
      vcode_add_arg(op, args[i]);
362✔
6002

6003
   return (op->result = vcode_add_reg(vtype_trigger()));
217✔
6004
}
6005

6006
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
34✔
6007
{
6008
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
34✔
6009
   vcode_add_arg(op, left);
34✔
6010
   vcode_add_arg(op, right);
34✔
6011

6012
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
34✔
6013
                "or trigger left argument must be trigger");
6014
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
34✔
6015
                "or trigger right argument must be trigger");
6016

6017
   return (op->result = vcode_add_reg(vtype_trigger()));
34✔
6018
}
6019

6020
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
63✔
6021
{
6022
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
63✔
6023
   vcode_add_arg(op, left);
63✔
6024
   vcode_add_arg(op, right);
63✔
6025

6026
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
63✔
6027
                "cmp trigger left argument must be signal");
6028
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
63✔
6029
                "cmp trigger right argument must be integer");
6030

6031
   return (op->result = vcode_add_reg(vtype_trigger()));
63✔
6032
}
6033

6034
void emit_add_trigger(vcode_reg_t trigger)
365✔
6035
{
6036
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
365✔
6037
   vcode_add_arg(op, trigger);
365✔
6038

6039
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
365✔
6040
                "add trigger argument must be trigger");
6041
}
365✔
6042

6043
vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective)
270✔
6044
{
6045
   op_t *op = vcode_add_op(VCODE_OP_PORT_CONVERSION);
270✔
6046
   vcode_add_arg(op, driving);
270✔
6047
   if (effective != VCODE_INVALID_REG && effective != driving)
270✔
6048
      vcode_add_arg(op, effective);
18✔
6049

6050
   VCODE_ASSERT(vcode_reg_kind(driving) == VCODE_TYPE_CLOSURE,
270✔
6051
                "port conversion argument must be a closure");
6052
   VCODE_ASSERT(effective == VCODE_INVALID_REG
270✔
6053
                || vcode_reg_kind(effective) == VCODE_TYPE_CLOSURE,
6054
                "port conversion argument must be a closure");
6055

6056
   return (op->result = vcode_add_reg(vtype_conversion()));
270✔
6057
}
6058

6059
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
200✔
6060
                               vcode_type_t type, vcode_type_t bounds)
6061
{
6062
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
200✔
6063
   vcode_add_arg(op, locus);
200✔
6064
   op->type  = type;
200✔
6065
   op->ident = scope;
200✔
6066

6067
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
200✔
6068
                "bind external argument must be locus");
6069

6070
   op->result = vcode_add_reg(vtype_pointer(type));
200✔
6071
   vcode_reg_data(op->result)->bounds = bounds;
200✔
6072
   return op->result;
200✔
6073
}
6074

6075
void emit_put_conversion(vcode_reg_t cf, vcode_reg_t target, vcode_reg_t count,
405✔
6076
                         vcode_reg_t values)
6077
{
6078
   op_t *op = vcode_add_op(VCODE_OP_PUT_CONVERSION);
405✔
6079
   vcode_add_arg(op, cf);
405✔
6080
   vcode_add_arg(op, target);
405✔
6081
   vcode_add_arg(op, count);
405✔
6082
   vcode_add_arg(op, values);
405✔
6083

6084
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
405✔
6085
                "put conversion target is not signal");
6086
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
405✔
6087
                "put conversion net count is not offset type");
6088
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
405✔
6089
                "signal cannot be values argument for put conversion");
6090
   VCODE_ASSERT(vcode_reg_kind(cf) == VCODE_TYPE_CONVERSION,
405✔
6091
                "cf argument to put conversion must be conversion function");
6092
}
405✔
6093

6094
void emit_convert_in(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
345✔
6095
{
6096
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_IN);
345✔
6097
   vcode_add_arg(op, conv);
345✔
6098
   vcode_add_arg(op, nets);
345✔
6099
   vcode_add_arg(op, count);
345✔
6100

6101
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
345✔
6102
                "conv argument to convert must be a port conversion");
6103
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
345✔
6104
                "nets argument to convert must be a signal");
6105
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
345✔
6106
                "count argument to convert must be offset");
6107
}
345✔
6108

6109
void emit_convert_out(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
387✔
6110
{
6111
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_OUT);
387✔
6112
   vcode_add_arg(op, conv);
387✔
6113
   vcode_add_arg(op, nets);
387✔
6114
   vcode_add_arg(op, count);
387✔
6115

6116
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
387✔
6117
                "conv argument to convert must be a port conversion");
6118
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
387✔
6119
                "nets argument to convert must be a signal");
6120
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
387✔
6121
                "count argument to convert must be offset");
6122
}
387✔
6123

6124
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
272✔
6125
{
6126
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
272✔
6127
   vcode_add_arg(op, spec);
272✔
6128
   vcode_add_arg(op, length);
272✔
6129
   if (locus != VCODE_INVALID_REG)
272✔
6130
      vcode_add_arg(op, locus);
137✔
6131

6132
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
272✔
6133
                "spec argument to bind foreign must be a pointer");
6134
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
272✔
6135
                "length argument to bind foreign must be offset");
6136
   VCODE_ASSERT(locus == VCODE_INVALID_REG
272✔
6137
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6138
                "locus argument to bind foreign value must be a debug locus");
6139
}
272✔
6140

6141
vcode_reg_t emit_instance_name(vcode_reg_t kind)
812✔
6142
{
6143
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
812✔
6144
   vcode_add_arg(op, kind);
812✔
6145

6146
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
812✔
6147
                "kind argument to instance name must be offset");
6148

6149
   vcode_type_t vchar = vtype_char();
812✔
6150
   return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar)));
812✔
6151
}
6152

6153
void emit_deposit_signal(vcode_reg_t signal, vcode_reg_t count,
177✔
6154
                         vcode_reg_t values)
6155
{
6156
   op_t *op = vcode_add_op(VCODE_OP_DEPOSIT_SIGNAL);
177✔
6157
   vcode_add_arg(op, signal);
177✔
6158
   vcode_add_arg(op, count);
177✔
6159
   vcode_add_arg(op, values);
177✔
6160

6161
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
177✔
6162
                "deposit signal target is not signal");
6163
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
177✔
6164
                "deposit signal count is not offset type");
6165
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
177✔
6166
                "signal cannot be values argument for deposit signal");
6167
}
177✔
6168

6169
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
29,746✔
6170
{
6171
   vcode_state_t state;
29,746✔
6172
   vcode_state_save(&state);
29,746✔
6173

6174
   vcode_select_unit(vu);
29,746✔
6175

6176
   const int nblocks = vcode_count_blocks();
29,746✔
6177
   for (int i = 0; i < nblocks; i++) {
139,500✔
6178
      vcode_select_block(i);
109,754✔
6179

6180
      const int nops = vcode_count_ops();
109,754✔
6181
      for (int op = 0; op < nops; op++) {
1,517,194✔
6182
         switch (vcode_get_op(op)) {
1,407,440✔
6183
         case VCODE_OP_LINK_PACKAGE:
9,583✔
6184
            (*fn)(vcode_get_ident(op), ctx);
9,583✔
6185
            break;
9,583✔
6186
         case VCODE_OP_FCALL:
52,728✔
6187
         case VCODE_OP_PCALL:
6188
         case VCODE_OP_CLOSURE:
6189
         case VCODE_OP_PROTECTED_INIT:
6190
         case VCODE_OP_PACKAGE_INIT:
6191
         case VCODE_OP_FUNCTION_TRIGGER:
6192
            (*fn)(vcode_get_func(op), ctx);
52,728✔
6193
            break;
52,728✔
6194
         default:
6195
            break;
6196
         }
6197
      }
6198
   }
6199

6200
   vcode_state_restore(&state);
29,746✔
6201
}
29,746✔
6202

6203
#ifdef DEBUG
UNCOV
6204
static void shape_mismatch(vcode_unit_t vu, vcode_unit_t shape,
×
6205
                           const char *fmt, ...)
6206
{
UNCOV
6207
   vcode_select_unit(vu);
×
UNCOV
6208
   vcode_dump();
×
6209

6210
   vcode_select_unit(shape);
×
UNCOV
6211
   vcode_dump();
×
6212

6213
   va_list ap;
×
UNCOV
6214
   va_start(ap, fmt);
×
6215

6216
   diag_t *d = diag_new(DIAG_FATAL, NULL);
×
UNCOV
6217
   diag_printf(d, "instance %s does not match shape %s", istr(vu->name),
×
6218
               istr(shape->name));
6219
   diag_stacktrace(d, true);
×
UNCOV
6220
   diag_vhint(d, NULL, fmt, ap);
×
6221
   diag_emit(d);
×
6222

6223
   va_end(ap);
×
6224

6225
   fatal_exit(1);
×
6226
}
6227
#endif
6228

6229
void vcode_check_shape(vcode_unit_t vu, vcode_unit_t shape)
90✔
6230
{
6231
#ifdef DEBUG
6232
   assert(shape->kind == VCODE_UNIT_SHAPE);
90✔
6233
   assert(vu->kind == VCODE_UNIT_INSTANCE);
90✔
6234

6235
   if (shape->vars.count <= vu->vars.count) {
90✔
6236
      for (int i = 0; i < shape->vars.count; i++) {
371✔
6237
         var_t *v = var_array_nth_ptr(&(vu->vars), i);
281✔
6238
         var_t *s = var_array_nth_ptr(&(shape->vars), i);
281✔
6239

6240
         if (v->name != s->name)
281✔
UNCOV
6241
            shape_mismatch(vu, shape, "var %d name %s != %s", i, istr(v->name),
×
6242
                           istr(s->name));
6243
         else if (v->flags != s->flags)
281✔
UNCOV
6244
            shape_mismatch(vu, shape, "var %d flags %x != %x", i, v->flags,
×
6245
                           s->flags);
6246
         // XXX: not possible to compare types at the moment
6247
      }
6248
   }
6249
   else
UNCOV
6250
      shape_mismatch(vu, shape, "shape vars %d > unit vars %d",
×
6251
                     shape->vars.count, vu->vars.count);
6252

6253
   if (shape->context != NULL)
90✔
UNCOV
6254
      vcode_check_shape(vu->context, shape->context);
×
6255
#endif
6256
}
90✔
6257

6258
#if VCODE_CHECK_UNIONS
6259
#define OP_USE_COUNT_U0(x)                                              \
6260
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6261
#define OP_USE_COUNT_U1(x)                                              \
6262
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6263
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6264
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6265

6266
__attribute__((constructor))
6267
static void vcode_check_unions(void)
6268
{
6269
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6270
   for (int i = 0; i < 256; i++) {
6271
      assert(OP_USE_COUNT_U0(i) <= 1);
6272
      assert(OP_USE_COUNT_U1(i) <= 1);
6273
   }
6274
}
6275
#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