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

nickg / nvc / 27865744029

20 Jun 2026 08:32AM UTC coverage: 92.264% (-0.005%) from 92.269%
27865744029

push

github

nickg
Bump version to 1.21.1

78741 of 85343 relevant lines covered (92.26%)

642699.33 hits per line

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

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

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

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

36
DECLARE_AND_DEFINE_ARRAY(vcode_reg);
16,655,397✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_block);
509,503✔
38
DECLARE_AND_DEFINE_ARRAY(vcode_type);
129,467✔
39

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

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

107
DECLARE_AND_DEFINE_ARRAY(op);
18,045,068✔
108

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

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

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

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

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

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

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

178
DECLARE_AND_DEFINE_ARRAY(param);
43,975✔
179
DECLARE_AND_DEFINE_ARRAY(var);
811,655✔
180
DECLARE_AND_DEFINE_ARRAY(reg);
13,959,915✔
181
DECLARE_AND_DEFINE_ARRAY(block);
205,352✔
182
DECLARE_AND_DEFINE_ARRAY(vtype);
36,207,765✔
183
DECLARE_AND_DEFINE_ARRAY(vstamp);
2,239,068✔
184

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

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

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

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

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

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

233
#define VCODE_CHECK_UNIONS 0
234

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

238
static inline int64_t sadd64(int64_t a, int64_t b)
57,586✔
239
{
240
   int64_t result;
57,586✔
241
   if (__builtin_add_overflow(a, b, &result))
57,586✔
242
      return b < 0 ? INT64_MIN : INT64_MAX;
14,676✔
243

244
   return result;
245
}
246

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

253
   return result;
254
}
255

256
static inline int64_t smul64(int64_t a, int64_t b)
23,432✔
257
{
258
   int64_t result;
23,432✔
259
   if (__builtin_mul_overflow(a, b, &result))
23,432✔
260
      return (a > 0 && b > 0) || (a < 0 && b < 0) ? INT64_MAX : INT64_MIN;
7,466✔
261

262
   return result;
263
}
264

265
static vcode_reg_t vcode_add_reg(vcode_type_t type, vcode_stamp_t stamp)
2,179,970✔
266
{
267
   assert(active_unit != NULL);
2,179,970✔
268

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

275
   return reg;
2,179,970✔
276
}
277

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

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

290
   VCODE_ASSERT(
2,850,471✔
291
      !vcode_block_finished(),
292
      "attempt to add to already finished block %d", active_block);
293

294
   block_t *block = vcode_block_data();
2,850,471✔
295

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

302
   return op;
2,850,471✔
303
}
304

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

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

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

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

324
static op_t *vcode_find_definition(vcode_reg_t reg)
3,043,458✔
325
{
326
   for (int i = active_block; i >= 0; i--) {
3,082,406✔
327
      block_t *b = &(active_unit->blocks.items[i]);
3,080,794✔
328
      for (int j = b->ops.count - 1; j >= 0; j--) {
64,460,861✔
329
         if (b->ops.items[j].result == reg)
64,421,913✔
330
            return &(b->ops.items[j]);
3,041,846✔
331
      }
332
   }
333

334
   return NULL;
335
}
336

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

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

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

367
   int depth = MASK_CONTEXT(type);
8,813,438✔
368
   assert(depth <= unit->depth);
8,813,438✔
369
   while (depth != unit->depth)
10,046,416✔
370
      unit = unit->context;
1,232,978✔
371

372
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
8,813,438✔
373
}
374

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

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

383
   int depth = MASK_CONTEXT(stamp);
1,730,467✔
384
   assert(depth <= unit->depth);
1,730,467✔
385
   while (depth != unit->depth)
1,773,369✔
386
      unit = unit->context;
42,902✔
387

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

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

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

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

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

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

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

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

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

441
         vcode_select_unit(vu);
824✔
442

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

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

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

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

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

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

468
         // Any store to this variable must be heap allocated
469
         for (int i = 0; i < active_unit->blocks.count; i++) {
23,418✔
470
            block_t *b = &(active_unit->blocks.items[i]);
21,968✔
471
            for (int j = 0; j < b->ops.count; j++) {
301,356✔
472
               op_t *op = &(b->ops.items[j]);
279,388✔
473
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
279,388✔
474
                  vcode_heap_allocate(op->args.items[0]);
1,450✔
475

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

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

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

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

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

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

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

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

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

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

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

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

574
   if (unit == active_unit)
78,461✔
575
      vcode_close();
14,388✔
576

577
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
96,970✔
578
      assert(it->context == unit);
18,509✔
579
      it->context = NULL;
18,509✔
580
   }
581
   unit->children = NULL;
78,461✔
582

583
   if (unit->context != NULL) {
78,461✔
584
      vcode_unit_t *it = &(unit->context->children);
21,339✔
585
      for (; *it != NULL && *it != unit; it = &((*it)->next))
54,630✔
586
         ;
587
      assert(*it != NULL);
21,339✔
588
      *it = (*it)->next;
21,339✔
589
   }
590

591
   for (unsigned i = 0; i < unit->blocks.count; i++) {
283,787✔
592
      block_t *b = &(unit->blocks.items[i]);
205,326✔
593

594
      for (unsigned j = 0; j < b->ops.count; j++) {
2,935,927✔
595
         op_t *o = &(b->ops.items[j]);
2,730,601✔
596
         if (OP_HAS_COMMENT(o->kind))
2,730,601✔
597
            free(o->comment);
323,843✔
598
         if (OP_HAS_TARGET(o->kind))
2,730,601✔
599
            free(o->targets.items);
119,076✔
600
         free(o->args.items);
2,730,601✔
601
      }
602
      free(b->ops.items);
205,326✔
603
   }
604
   free(unit->blocks.items);
78,461✔
605

606
   for (unsigned i = 0; i < unit->types.count; i++) {
590,753✔
607
      vtype_t *vt = &(unit->types.items[i]);
512,292✔
608
      if (vt->kind == VCODE_TYPE_RECORD)
512,292✔
609
         free(vt->fields.items);
9,155✔
610
   }
611
   free(unit->types.items);
78,461✔
612

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

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

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

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

636
vcode_type_t vcode_reg_type(vcode_reg_t reg)
8,997,612✔
637
{
638
   return vcode_reg_data(reg)->type;
8,997,612✔
639
}
640

641
vtype_kind_t vcode_reg_kind(vcode_reg_t reg)
2,338,708✔
642
{
643
   return vtype_kind(vcode_reg_type(reg));
2,338,708✔
644
}
645

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

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

655
   if (r->stamp == VCODE_INVALID_STAMP)
1,355,265✔
656
      return false;
657

658
   const vstamp_t *s = vcode_stamp_data(r->stamp);
1,060,951✔
659

660
   if (s->kind != VCODE_STAMP_INT)
1,060,951✔
661
      return false;
662

663
   if (s->u.intg.low == s->u.intg.high) {
1,026,343✔
664
      if (value) *value = s->u.intg.low;
802,504✔
665
      return true;
802,504✔
666
   }
667
   else
668
      return false;
669
}
670

671
bool vcode_reg_bounds(vcode_reg_t reg, int64_t *low, int64_t *high)
615,261✔
672
{
673
   reg_t *r = vcode_reg_data(reg);
615,261✔
674
   if (r->stamp == VCODE_INVALID_STAMP) {
615,261✔
675
      vtype_t *t = vcode_type_data(r->type);
107,414✔
676
      if (t->kind == VCODE_TYPE_INT || t->kind == VCODE_TYPE_OFFSET) {
107,414✔
677
         *low = t->low;
106,024✔
678
         *high = t->high;
106,024✔
679
         return true;
106,024✔
680
      }
681
   }
682
   else {
683
      vstamp_t *s = vcode_stamp_data(r->stamp);
507,847✔
684
      if (s->kind == VCODE_STAMP_INT) {
507,847✔
685
         *low = s->u.intg.low;
507,303✔
686
         *high = s->u.intg.high;
507,303✔
687
         return true;
507,303✔
688
      }
689
   }
690

691
   return false;
692
}
693

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

714
   return false;
715
}
716

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

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

723
   int pruned = 0;
78,487✔
724
   do {
110,938✔
725
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
110,938✔
726
      pruned = 0;
110,938✔
727

728
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
449,547✔
729
         block_t *b = &(active_unit->blocks.items[i]);
338,609✔
730

731
         for (int j = b->ops.count - 1; j >= 0; j--) {
5,398,758✔
732
            op_t *o = &(b->ops.items[j]);
5,060,149✔
733

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

796
            default:
797
               break;
798
            }
799

800
            for (int k = 0; k < o->args.count; k++) {
15,173,771✔
801
               if (o->args.items[k] != VCODE_INVALID_REG)
10,113,622✔
802
                  uses[o->args.items[k]]++;
10,065,236✔
803
            }
804
         }
805
      }
806
   } while (pruned > 0);
110,938✔
807

808
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
283,839✔
809
      block_t *b = &(active_unit->blocks.items[i]);
205,352✔
810
      op_t *dst = &(b->ops.items[0]);
205,352✔
811
      size_t copied = 0;
205,352✔
812
      for (int j = 0; j < b->ops.count; j++) {
3,055,823✔
813
         const op_t *src = &(b->ops.items[j]);
2,850,471✔
814
         if (src->kind != (vcode_op_t)-1) {
2,850,471✔
815
            if (src != dst) {
2,730,738✔
816
               assert(dst < src);
946,171✔
817
               *dst = *src;
946,171✔
818
            }
819
            dst++;
2,730,738✔
820
            copied++;
2,730,738✔
821
         }
822
      }
823

824
      assert(copied <= b->ops.count);
205,352✔
825
      b->ops.count = copied;
205,352✔
826
   }
827
}
78,487✔
828

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

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

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

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

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

862
   return VCODE_INVALID_VAR;
863
}
864

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

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

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

880
vcode_op_t vcode_get_op(int op)
3,149,262✔
881
{
882
   return vcode_op_data(op)->kind;
3,149,262✔
883
}
884

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1007
bool vcode_block_finished(void)
3,022,975✔
1008
{
1009
   assert(active_unit != NULL);
3,022,975✔
1010
   assert(active_block != VCODE_INVALID_BLOCK);
3,022,975✔
1011

1012
   const block_t *b = &(active_unit->blocks.items[active_block]);
3,022,975✔
1013
   if (b->ops.count == 0)
3,022,975✔
1014
      return false;
1015
   else {
1016
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
2,744,184✔
1017
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
2,744,184✔
1018
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
2,744,160✔
1019
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
1020
         || kind == VCODE_OP_UNREACHABLE;
5,488,344✔
1021
   }
1022
}
1023

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1186
   return col;
1187
}
1188

1189
static void vcode_dump_tab(int col, int to_col)
1190
{
1191
   if (col >= to_col)
1192
      printf(" ");
1193
   else {
1194
      while (col < to_col)
1195
         col += printf(" ");
1196
   }
1197
}
1198

1199
static void vcode_dump_comment(int col)
1200
{
1201
   vcode_dump_tab(col, 40);
1202
   nvc_printf("$cyan$// ");
1203
}
1204

1205
static void vcode_dump_type(int col, vcode_type_t type, vcode_stamp_t stamp)
1206
{
1207
   vcode_dump_comment(col);
1208
   vcode_dump_one_type(type);
1209

1210
   if (stamp == VCODE_INVALID_STAMP)
1211
      return;
1212

1213
   printf(" => ");
1214

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

1227
   case VCODE_STAMP_REAL:
1228
      if (s->u.real.low != s->u.real.high)
1229
         printf("%g..%g", s->u.real.low, s->u.real.high);
1230
      else
1231
         printf("%g", s->u.real.low);
1232
      break;
1233

1234
   default:
1235
      should_not_reach_here();
1236
   }
1237
}
1238

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

1247
static int vcode_dump_var(vcode_var_t var, int hops)
1248
{
1249
   vcode_unit_t owner = active_unit;
1250
   while (owner && hops--)
1251
      owner = owner->context;
1252

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

1261
void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg)
1262
{
1263
   assert(active_unit != NULL);
1264

1265
   const vcode_unit_t vu = active_unit;
1266
   vcode_block_t old_block = active_block;
1267

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

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

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

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

1324
   if (vu->result != VCODE_INVALID_TYPE) {
1325
      nvc_printf("Result     $cyan$");
1326
      vcode_dump_one_type(vu->result);
1327
      nvc_printf("$$\n");
1328
   }
1329

1330
   if (vu->kind == VCODE_UNIT_FUNCTION
1331
       || vu->kind == VCODE_UNIT_PROCEDURE
1332
       || vu->kind == VCODE_UNIT_PROPERTY
1333
       || (vu->kind == VCODE_UNIT_PROTECTED && vu->params.count > 0)
1334
       || (vu->kind == VCODE_UNIT_PROCESS && vu->params.count > 0)) {
1335

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

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

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

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

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

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

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

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

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

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

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

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

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

1482
         case VCODE_OP_POP_SCOPE:
1483
            {
1484
               printf("%s", vcode_op_string(op->kind));
1485
            }
1486
            break;
1487

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

1510
         case VCODE_OP_RESOLUTION_WRAPPER:
1511
            {
1512
               col += vcode_dump_reg(op->result);
1513
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
1514
               col += vcode_dump_reg(op->args.items[0]);
1515
               col += printf(" nlits ");
1516
               col += vcode_dump_reg(op->args.items[1]);
1517
               vcode_dump_result_type(col, op);
1518
            }
1519
            break;
1520

1521
         case VCODE_OP_CLOSURE:
1522
         case VCODE_OP_PROTECTED_INIT:
1523
            {
1524
               col += vcode_dump_reg(op->result);
1525
               col += nvc_printf(" := %s $magenta$%s$$ context ",
1526
                                 vcode_op_string(op->kind), istr(op->func));
1527
               col += vcode_dump_reg(op->args.items[0]);
1528
               if (op->args.count >= 3) {
1529
                  col += printf(" path " );
1530
                  col += vcode_dump_reg(op->args.items[1]);
1531
                  col += printf(" instance " );
1532
                  col += vcode_dump_reg(op->args.items[2]);
1533
               }
1534
               vcode_dump_result_type(col, op);
1535
            }
1536
            break;
1537

1538
         case VCODE_OP_PACKAGE_INIT:
1539
            {
1540
               col += vcode_dump_reg(op->result);
1541
               col += nvc_printf(" := %s $magenta$%s$$",
1542
                                   vcode_op_string(op->kind), istr(op->func));
1543
               if (op->args.count > 0) {
1544
                  col += printf(" context " );
1545
                  col += vcode_dump_reg(op->args.items[0]);
1546
               }
1547
               vcode_dump_result_type(col, op);
1548
            }
1549
            break;
1550

1551
         case VCODE_OP_PROCESS_INIT:
1552
            {
1553
               printf("%s ", vcode_op_string(op->kind));
1554
               vcode_dump_reg(op->args.items[0]);
1555
               printf(" locus ");
1556
               vcode_dump_reg(op->args.items[1]);
1557
            }
1558
            break;
1559

1560
         case VCODE_OP_PROTECTED_FREE:
1561
            {
1562
               printf("%s ", vcode_op_string(op->kind));
1563
               vcode_dump_reg(op->args.items[0]);
1564
            }
1565
            break;
1566

1567
         case VCODE_OP_WAIT:
1568
            {
1569
               nvc_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1570
                            op->targets.items[0]);
1571
            }
1572
            break;
1573

1574
         case VCODE_OP_SCHED_PROCESS:
1575
            {
1576
               nvc_printf("%s after ", vcode_op_string(op->kind));
1577
               vcode_dump_reg(op->args.items[0]);
1578
            }
1579
            break;
1580

1581
         case VCODE_OP_JUMP:
1582
            {
1583
               nvc_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1584
                            op->targets.items[0]);
1585
            }
1586
            break;
1587

1588
         case VCODE_OP_COND:
1589
            {
1590
               printf("%s ", vcode_op_string(op->kind));
1591
               vcode_dump_reg(op->args.items[0]);
1592
               nvc_printf(" then $yellow$%d$$ else $yellow$%d$$",
1593
                            op->targets.items[0], op->targets.items[1]);
1594
            }
1595
            break;
1596

1597
         case VCODE_OP_ASSERT:
1598
            {
1599
               printf("%s ", vcode_op_string(op->kind));
1600
               vcode_dump_reg(op->args.items[0]);
1601
               if (op->args.items[2] != VCODE_INVALID_REG) {
1602
                  printf(" report ");
1603
                  vcode_dump_reg(op->args.items[2]);
1604
                  printf(" length ");
1605
                  vcode_dump_reg(op->args.items[3]);
1606
               }
1607
               printf(" severity ");
1608
               vcode_dump_reg(op->args.items[1]);
1609
               printf(" locus ");
1610
               vcode_dump_reg(op->args.items[4]);
1611
               if (op->args.count > 5) {
1612
                  printf(" hint ");
1613
                  vcode_dump_reg(op->args.items[5]);
1614
                  printf(" ");
1615
                  vcode_dump_reg(op->args.items[6]);
1616
               }
1617
            }
1618
            break;
1619

1620
         case VCODE_OP_REPORT:
1621
            {
1622
               printf("%s ", vcode_op_string(op->kind));
1623
               vcode_dump_reg(op->args.items[1]);
1624
               printf(" length ");
1625
               vcode_dump_reg(op->args.items[2]);
1626
               printf(" severity ");
1627
               vcode_dump_reg(op->args.items[0]);
1628
               printf(" locus ");
1629
               vcode_dump_reg(op->args.items[3]);
1630
            }
1631
            break;
1632

1633
         case VCODE_OP_LOAD:
1634
            {
1635
               col += vcode_dump_reg(op->result);
1636
               col += printf(" := %s ", vcode_op_string(op->kind));
1637
               col += vcode_dump_var(op->address, 0);
1638
               vcode_dump_result_type(col, op);
1639
            }
1640
            break;
1641

1642
         case VCODE_OP_LOAD_INDIRECT:
1643
            {
1644
               col += vcode_dump_reg(op->result);
1645
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
1646
               col += vcode_dump_reg(op->args.items[0]);
1647
               vcode_dump_result_type(col, op);
1648
            }
1649
            break;
1650

1651
         case VCODE_OP_STORE:
1652
            {
1653
               vcode_dump_var(op->address, 0);
1654
               printf(" := %s ", vcode_op_string(op->kind));
1655
               vcode_dump_reg(op->args.items[0]);
1656
            }
1657
            break;
1658

1659
         case VCODE_OP_STORE_INDIRECT:
1660
            {
1661
               vcode_dump_reg(op->args.items[1]);
1662
               printf(" := %s ", vcode_op_string(op->kind));
1663
               vcode_dump_reg(op->args.items[0]);
1664
            }
1665
            break;
1666

1667
         case VCODE_OP_INDEX:
1668
            {
1669
               col += vcode_dump_reg(op->result);
1670
               col += printf(" := %s ", vcode_op_string(op->kind));
1671
               col += vcode_dump_var(op->address, 0);
1672
               if (op->args.count > 0) {
1673
                  col += printf(" + ");
1674
                  col += vcode_dump_reg(op->args.items[0]);
1675
               }
1676
               vcode_dump_result_type(col, op);
1677
            }
1678
            break;
1679

1680
         case VCODE_OP_MUL:
1681
         case VCODE_OP_ADD:
1682
         case VCODE_OP_SUB:
1683
         case VCODE_OP_DIV:
1684
         case VCODE_OP_EXP:
1685
         case VCODE_OP_MOD:
1686
         case VCODE_OP_REM:
1687
         case VCODE_OP_OR:
1688
         case VCODE_OP_AND:
1689
         case VCODE_OP_XOR:
1690
         case VCODE_OP_XNOR:
1691
         case VCODE_OP_NAND:
1692
         case VCODE_OP_NOR:
1693
            {
1694
               col += vcode_dump_reg(op->result);
1695
               col += printf(" := %s ", vcode_op_string(op->kind));
1696
               col += vcode_dump_reg(op->args.items[0]);
1697
               switch (op->kind) {
1698
               case VCODE_OP_MUL:  col += printf(" * "); break;
1699
               case VCODE_OP_ADD:  col += printf(" + "); break;
1700
               case VCODE_OP_SUB:  col += printf(" - "); break;
1701
               case VCODE_OP_DIV:  col += printf(" / "); break;
1702
               case VCODE_OP_EXP:  col += printf(" ** "); break;
1703
               case VCODE_OP_MOD:  col += printf(" %% "); break;
1704
               case VCODE_OP_REM:  col += printf(" %% "); break;
1705
               case VCODE_OP_OR:   col += printf(" || "); break;
1706
               case VCODE_OP_AND:  col += printf(" && "); break;
1707
               case VCODE_OP_XOR:  col += printf(" ^ "); break;
1708
               case VCODE_OP_XNOR: col += printf(" !^ "); break;
1709
               case VCODE_OP_NAND: col += printf(" !& "); break;
1710
               case VCODE_OP_NOR:  col += printf(" !| "); break;
1711
               default: break;
1712
               }
1713
               col += vcode_dump_reg(op->args.items[1]);
1714
               vcode_dump_result_type(col, op);
1715
            }
1716
            break;
1717

1718
         case VCODE_OP_TRAP_ADD:
1719
         case VCODE_OP_TRAP_SUB:
1720
         case VCODE_OP_TRAP_MUL:
1721
         case VCODE_OP_TRAP_EXP:
1722
            {
1723
               col += vcode_dump_reg(op->result);
1724
               col += printf(" := %s ", vcode_op_string(op->kind));
1725
               col += vcode_dump_reg(op->args.items[0]);
1726
               switch (op->kind) {
1727
               case VCODE_OP_TRAP_ADD: col += printf(" + "); break;
1728
               case VCODE_OP_TRAP_SUB: col += printf(" - "); break;
1729
               case VCODE_OP_TRAP_MUL: col += printf(" * "); break;
1730
               case VCODE_OP_TRAP_EXP: col += printf(" ** "); break;
1731
               default: break;
1732
               }
1733
               col += vcode_dump_reg(op->args.items[1]);
1734
               col += printf(" locus ");
1735
               col += vcode_dump_reg(op->args.items[2]);
1736
               vcode_dump_result_type(col, op);
1737
            }
1738
            break;
1739

1740
         case VCODE_OP_NOT:
1741
            {
1742
               col += vcode_dump_reg(op->result);
1743
               col += printf(" := %s ", vcode_op_string(op->kind));
1744
               col += vcode_dump_reg(op->args.items[0]);
1745
               vcode_dump_result_type(col, op);
1746
            }
1747
            break;
1748

1749
         case VCODE_OP_COMMENT:
1750
            {
1751
               nvc_printf("$cyan$// %s$$ ", op->comment);
1752
            }
1753
            break;
1754

1755
         case VCODE_OP_CONST_ARRAY:
1756
         case VCODE_OP_CONST_RECORD:
1757
            {
1758
               col += vcode_dump_reg(op->result);
1759
               col += printf(" := const %c",
1760
                             op->kind == VCODE_OP_CONST_ARRAY ? '[' : '{');
1761
               for (int k = 0; k < op->args.count; k++) {
1762
                  if (k > 0)
1763
                     col += printf(",");
1764
                  col += vcode_dump_reg(op->args.items[k]);
1765
               }
1766

1767
               putchar(op->kind == VCODE_OP_CONST_ARRAY ? ']' : '}');
1768
               vcode_dump_result_type(col + 1, op);
1769
            }
1770
            break;
1771

1772
         case VCODE_OP_CONST_REP:
1773
            {
1774
               col += vcode_dump_reg(op->result);
1775
               col += printf(" := const [");
1776
               col += vcode_dump_reg(op->args.items[0]);
1777
               col += printf("]*%"PRIi64, op->value);
1778
               vcode_dump_result_type(col, op);
1779
            }
1780
            break;
1781

1782
         case VCODE_OP_ADDRESS_OF:
1783
         case VCODE_OP_CAST:
1784
            {
1785
               col += vcode_dump_reg(op->result);
1786
               col += printf(" := %s ", vcode_op_string(op->kind));
1787
               col += vcode_dump_reg(op->args.items[0]);
1788
               vcode_dump_result_type(col, op);
1789
            }
1790
            break;
1791

1792
         case VCODE_OP_RETURN:
1793
            {
1794
               printf("%s ", vcode_op_string(op->kind));
1795
               if (op->args.count > 0)
1796
                  vcode_dump_reg(op->args.items[0]);
1797
            }
1798
            break;
1799

1800
         case VCODE_OP_SCHED_WAVEFORM:
1801
            {
1802
               printf("%s ", vcode_op_string(op->kind));
1803
               vcode_dump_reg(op->args.items[0]);
1804
               printf(" count ");
1805
               vcode_dump_reg(op->args.items[1]);
1806
               printf(" values ");
1807
               vcode_dump_reg(op->args.items[2]);
1808
               printf(" reject ");
1809
               vcode_dump_reg(op->args.items[3]);
1810
               printf(" after ");
1811
               vcode_dump_reg(op->args.items[4]);
1812
            }
1813
            break;
1814

1815
         case VCODE_OP_FORCE:
1816
         case VCODE_OP_RELEASE:
1817
         case VCODE_OP_PUT_DRIVER:
1818
         case VCODE_OP_DEPOSIT_SIGNAL:
1819
            {
1820
               printf("%s ", vcode_op_string(op->kind));
1821
               vcode_dump_reg(op->args.items[0]);
1822
               printf(" count ");
1823
               vcode_dump_reg(op->args.items[1]);
1824
               if (op->args.count > 2) {
1825
                  printf(" values ");
1826
                  vcode_dump_reg(op->args.items[2]);
1827
               }
1828
            }
1829
            break;
1830

1831
         case VCODE_OP_DISCONNECT:
1832
            {
1833
               printf("%s ", vcode_op_string(op->kind));
1834
               vcode_dump_reg(op->args.items[0]);
1835
               printf(" count ");
1836
               vcode_dump_reg(op->args.items[1]);
1837
               printf(" reject ");
1838
               vcode_dump_reg(op->args.items[2]);
1839
               printf(" after ");
1840
               vcode_dump_reg(op->args.items[3]);
1841
            }
1842
            break;
1843

1844
         case VCODE_OP_NEG:
1845
         case VCODE_OP_TRAP_NEG:
1846
         case VCODE_OP_ABS:
1847
         case VCODE_OP_RESOLVED:
1848
         case VCODE_OP_LAST_VALUE:
1849
            {
1850
               col += vcode_dump_reg(op->result);
1851
               col += printf(" := %s ", vcode_op_string(op->kind));
1852
               col += vcode_dump_reg(op->args.items[0]);
1853
               if (op->args.count > 1) {
1854
                  col += printf(" locus ");
1855
                  col += vcode_dump_reg(op->args.items[1]);
1856
               }
1857
               vcode_dump_result_type(col, op);
1858
            }
1859
            break;
1860

1861
         case VCODE_OP_SELECT:
1862
            {
1863
               col += vcode_dump_reg(op->result);
1864
               col += printf(" := %s ", vcode_op_string(op->kind));
1865
               col += vcode_dump_reg(op->args.items[0]);
1866
               col += printf(" then ");
1867
               col += vcode_dump_reg(op->args.items[1]);
1868
               col += printf(" else ");
1869
               col += vcode_dump_reg(op->args.items[2]);
1870
               vcode_dump_result_type(col, op);
1871
            }
1872
            break;
1873

1874
         case VCODE_OP_WRAP:
1875
            {
1876
               col += vcode_dump_reg(op->result);
1877
               col += printf(" := %s ", vcode_op_string(op->kind));
1878
               col += vcode_dump_reg(op->args.items[0]);
1879
               col += printf(" [");
1880
               for (int i = 1; i < op->args.count; i += 3) {
1881
                  if (i > 1)
1882
                     col += printf(", ");
1883
                  col += vcode_dump_reg(op->args.items[i + 0]);
1884
                  col += printf(" ");
1885
                  col += vcode_dump_reg(op->args.items[i + 1]);
1886
                  col += printf(" ");
1887
                  col += vcode_dump_reg(op->args.items[i + 2]);
1888
               }
1889
               col += printf("]");
1890
               vcode_dump_result_type(col, op);
1891
            }
1892
            break;
1893

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

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

1916
         case VCODE_OP_VAR_UPREF:
1917
            {
1918
               col += vcode_dump_reg(op->result);
1919
               col += printf(" := %s %d, ", vcode_op_string(op->kind),
1920
                             op->hops);
1921
               col += vcode_dump_var(op->address, op->hops);
1922
               vcode_dump_result_type(col, op);
1923
            }
1924
            break;
1925

1926
         case VCODE_OP_CONTEXT_UPREF:
1927
            {
1928
               col += vcode_dump_reg(op->result);
1929
               col += printf(" := %s %d", vcode_op_string(op->kind), op->hops);
1930
               vcode_dump_result_type(col, op);
1931
            }
1932
            break;
1933

1934
         case VCODE_OP_ACTIVE:
1935
         case VCODE_OP_EVENT:
1936
         case VCODE_OP_DRIVING:
1937
            {
1938
               col += vcode_dump_reg(op->result);
1939
               col += printf(" := %s ", vcode_op_string(op->kind));
1940
               col += vcode_dump_reg(op->args.items[0]);
1941
               col += printf(" length ");
1942
               col += vcode_dump_reg(op->args.items[1]);
1943
               vcode_dump_result_type(col, op);
1944
            }
1945
            break;
1946

1947
         case VCODE_OP_RECORD_REF:
1948
            {
1949
               col += vcode_dump_reg(op->result);
1950
               col += printf(" := %s ", vcode_op_string(op->kind));
1951
               col += vcode_dump_reg(op->args.items[0]);
1952
               col += printf(" field %d", op->field);
1953
               vcode_dump_result_type(col, op);
1954
            }
1955
            break;
1956

1957
         case VCODE_OP_ARRAY_REF:
1958
            {
1959
               col += vcode_dump_reg(op->result);
1960
               col += printf(" := %s ", vcode_op_string(op->kind));
1961
               col += vcode_dump_reg(op->args.items[0]);
1962
               col += printf(" offset ");
1963
               col += vcode_dump_reg(op->args.items[1]);
1964
               vcode_dump_result_type(col, op);
1965
            }
1966
            break;
1967

1968
         case VCODE_OP_TABLE_REF:
1969
            {
1970
               col += vcode_dump_reg(op->result);
1971
               col += printf(" := %s ", vcode_op_string(op->kind));
1972
               col += vcode_dump_reg(op->args.items[0]);
1973
               col += printf(" stride ");
1974
               col += vcode_dump_reg(op->args.items[1]);
1975
               col += printf(" [");
1976
               for (int i = 2; i < op->args.count; i++) {
1977
                  if (i > 2) col += printf(", ");
1978
                  col += vcode_dump_reg(op->args.items[i]);
1979
               }
1980
               col += printf("]");
1981
               vcode_dump_result_type(col, op);
1982
            }
1983
            break;
1984

1985
         case VCODE_OP_COPY:
1986
            {
1987
               vcode_dump_reg(op->args.items[0]);
1988
               printf(" := %s ", vcode_op_string(op->kind));
1989
               vcode_dump_reg(op->args.items[1]);
1990
               if (op->args.count > 2) {
1991
                  printf(" count " );
1992
                  vcode_dump_reg(op->args.items[2]);
1993
               }
1994
            }
1995
            break;
1996

1997
         case VCODE_OP_SCHED_EVENT:
1998
         case VCODE_OP_CLEAR_EVENT:
1999
         case VCODE_OP_SCHED_ACTIVE:
2000
            {
2001
               printf("%s on ", vcode_op_string(op->kind));
2002
               vcode_dump_reg(op->args.items[0]);
2003
               printf(" count ");
2004
               vcode_dump_reg(op->args.items[1]);
2005
            }
2006
            break;
2007

2008
         case VCODE_OP_PCALL:
2009
            {
2010
               nvc_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
2011
                          istr(op->func));
2012
               for (int i = 0; i < op->args.count; i++) {
2013
                  printf("%s", i > 0 ? ", " : " ");
2014
                  vcode_dump_reg(op->args.items[i]);
2015
               }
2016
               if (op->targets.count > 0)
2017
                  nvc_printf(" resume $yellow$%d$$", op->targets.items[0]);
2018
            }
2019
            break;
2020

2021
         case VCODE_OP_RESUME:
2022
            {
2023
               nvc_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
2024
                            istr(op->func));
2025
            }
2026
            break;
2027

2028
         case VCODE_OP_MEMSET:
2029
            {
2030
               vcode_dump_reg(op->args.items[0]);
2031
               printf(" := %s ", vcode_op_string(op->kind));
2032
               vcode_dump_reg(op->args.items[1]);
2033
               printf(" length ");
2034
               vcode_dump_reg(op->args.items[2]);
2035
            }
2036
            break;
2037

2038
         case VCODE_OP_CASE:
2039
            {
2040
               printf("%s ", vcode_op_string(op->kind));
2041
               vcode_dump_reg(op->args.items[0]);
2042
               nvc_printf(" default $yellow$%d$$", op->targets.items[0]);
2043
               for (int i = 1; i < op->args.count; i++) {
2044
                  printf(" [");
2045
                  vcode_dump_reg(op->args.items[i]);
2046
                  nvc_printf(" $yellow$%d$$]", op->targets.items[i]);
2047
               }
2048
            }
2049
            break;
2050

2051
         case VCODE_OP_FILE_OPEN:
2052
            {
2053
               printf("%s ", vcode_op_string(op->kind));
2054
               vcode_dump_reg(op->args.items[0]);
2055
               printf(" name ");
2056
               vcode_dump_reg(op->args.items[1]);
2057
               printf(" length ");
2058
               vcode_dump_reg(op->args.items[2]);
2059
               printf(" kind ");
2060
               vcode_dump_reg(op->args.items[3]);
2061
               if (op->args.count == 5) {
2062
                  printf(" status ");
2063
                  vcode_dump_reg(op->args.items[4]);
2064
               }
2065
            }
2066
            break;
2067

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

2081
         case VCODE_OP_FILE_READ:
2082
            {
2083
               printf("%s ", vcode_op_string(op->kind));
2084
               vcode_dump_reg(op->args.items[0]);
2085
               printf(" ptr ");
2086
               vcode_dump_reg(op->args.items[1]);
2087
               if (op->args.count >= 3) {
2088
                  printf(" inlen ");
2089
                  vcode_dump_reg(op->args.items[2]);
2090
                  if (op->args.count >= 4) {
2091
                     printf(" outlen ");
2092
                     vcode_dump_reg(op->args.items[3]);
2093
                  }
2094
               }
2095
            }
2096
            break;
2097

2098
         case VCODE_OP_NULL:
2099
         case VCODE_OP_NEW:
2100
            {
2101
               col += vcode_dump_reg(op->result);
2102
               col += printf(" := %s", vcode_op_string(op->kind));
2103
               if (op->args.count == 1) {
2104
                  col += printf(" length ");
2105
                  col += vcode_dump_reg(op->args.items[0]);
2106
               }
2107
               vcode_dump_result_type(col, op);
2108
            }
2109
            break;
2110

2111
         case VCODE_OP_NULL_CHECK:
2112
            {
2113
               col += printf("%s ", vcode_op_string(op->kind));
2114
               col += vcode_dump_reg(op->args.items[0]);
2115
               col += printf(" locus ");
2116
               col += vcode_dump_reg(op->args.items[1]);
2117
            }
2118
            break;
2119

2120
         case VCODE_OP_DEALLOCATE:
2121
            {
2122
               col += printf("%s ", vcode_op_string(op->kind));
2123
               col += vcode_dump_reg(op->args.items[0]);
2124
            }
2125
            break;
2126

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

2136
         case VCODE_OP_LAST_EVENT:
2137
         case VCODE_OP_LAST_ACTIVE:
2138
         case VCODE_OP_DRIVING_VALUE:
2139
            {
2140
               col += vcode_dump_reg(op->result);
2141
               col += printf(" := %s ", vcode_op_string(op->kind));
2142
               col += vcode_dump_reg(op->args.items[0]);
2143
               if (op->args.count > 1) {
2144
                  col += printf(" length ");
2145
                  col += vcode_dump_reg(op->args.items[1]);
2146
               }
2147
               vcode_dump_result_type(col, op);
2148
            }
2149
            break;
2150

2151
         case VCODE_OP_ALIAS_SIGNAL:
2152
            {
2153
               printf("%s ", vcode_op_string(op->kind));
2154
               vcode_dump_reg(op->args.items[0]);
2155
               printf(" locus ");
2156
               vcode_dump_reg(op->args.items[1]);
2157
            }
2158
            break;
2159

2160
         case VCODE_OP_LENGTH_CHECK:
2161
            {
2162
               col += printf("%s left ", vcode_op_string(op->kind));
2163
               col += vcode_dump_reg(op->args.items[0]);
2164
               col += printf(" == right ");
2165
               col += vcode_dump_reg(op->args.items[1]);
2166
               col += printf(" locus ");
2167
               col += vcode_dump_reg(op->args.items[2]);
2168
               if (op->args.count > 3) {
2169
                  col += printf(" dim ");
2170
                  col += vcode_dump_reg(op->args.items[3]);
2171
               }
2172
            }
2173
            break;
2174

2175
         case VCODE_OP_EXPONENT_CHECK:
2176
         case VCODE_OP_ZERO_CHECK:
2177
            {
2178
               col += printf("%s ", vcode_op_string(op->kind));
2179
               col += vcode_dump_reg(op->args.items[0]);
2180
               col += printf(" locus ");
2181
               col += vcode_dump_reg(op->args.items[1]);
2182
            }
2183
            break;
2184

2185
         case VCODE_OP_INDEX_CHECK:
2186
         case VCODE_OP_RANGE_CHECK:
2187
            {
2188
               col += printf("%s ", vcode_op_string(op->kind));
2189
               col += vcode_dump_reg(op->args.items[0]);
2190
               col += printf(" left ");
2191
               col += vcode_dump_reg(op->args.items[1]);
2192
               col += printf(" right ");
2193
               col += vcode_dump_reg(op->args.items[2]);
2194
               col += printf(" dir ");
2195
               col += vcode_dump_reg(op->args.items[3]);
2196
               col += printf(" locus ");
2197
               col += vcode_dump_reg(op->args.items[4]);
2198
               if (op->args.items[5] != op->args.items[4]) {
2199
                  col += printf(" hint ");
2200
                  col += vcode_dump_reg(op->args.items[5]);
2201
               }
2202
            }
2203
            break;
2204

2205
         case VCODE_OP_DIR_CHECK:
2206
            {
2207
               col += printf("%s ", vcode_op_string(op->kind));
2208
               col += vcode_dump_reg(op->args.items[0]);
2209
               col += printf(" == ");
2210
               col += vcode_dump_reg(op->args.items[1]);
2211
               col += printf(" locus ");
2212
               col += vcode_dump_reg(op->args.items[2]);
2213
            }
2214
            break;
2215

2216
         case VCODE_OP_DEBUG_OUT:
2217
            {
2218
               col += printf("%s ", vcode_op_string(op->kind));
2219
               col += vcode_dump_reg(op->args.items[0]);
2220
            }
2221
            break;
2222

2223
         case VCODE_OP_COVER_STMT:
2224
         case VCODE_OP_COVER_BRANCH:
2225
         case VCODE_OP_COVER_EXPR:
2226
            {
2227
               printf("%s ", vcode_op_string(op->kind));
2228
               vcode_dump_reg(op->args.items[0]);
2229
               printf(" tag %u", op->tag);
2230
            }
2231
            break;
2232

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

2243
         case VCODE_OP_COVER_STATE:
2244
            {
2245
               printf("%s ", vcode_op_string(op->kind));
2246
               vcode_dump_reg(op->args.items[0]);
2247
               printf(" low ");
2248
               vcode_dump_reg(op->args.items[1]);
2249
               printf(" tag %u", op->tag);
2250
            }
2251
            break;
2252

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2400
         case VCODE_OP_BIND_FOREIGN:
2401
            {
2402
               nvc_printf("%s ", vcode_op_string(op->kind));
2403
               vcode_dump_reg(op->args.items[0]);
2404
               printf(" length ");
2405
               vcode_dump_reg(op->args.items[1]);
2406
               if (op->args.count > 2) {
2407
                  printf(" locus ");
2408
                  vcode_dump_reg(op->args.items[1]);
2409
               }
2410
            }
2411
            break;
2412

2413
         case VCODE_OP_INSTANCE_NAME:
2414
         case VCODE_OP_BIND_EXTERNAL:
2415
            {
2416
               col += vcode_dump_reg(op->result);
2417
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
2418
               col += vcode_dump_reg(op->args.items[0]);
2419
               col += nvc_printf(" scope $magenta$%s$$ ", istr(op->ident));
2420
               for (int i = 1; i < op->args.count; i++) {
2421
                  if (i > 1) col += printf(", ");
2422
                  col += vcode_dump_reg(op->args.items[i]);
2423
               }
2424
               vcode_dump_result_type(col, op);
2425
            }
2426
            break;
2427

2428
         case VCODE_OP_GET_COUNTERS:
2429
            {
2430
               col += vcode_dump_reg(op->result);
2431
               col += nvc_printf(":= %s $magenta$%s$$",
2432
                                 vcode_op_string(op->kind), istr(op->ident));
2433
               vcode_dump_result_type(col, op);
2434
            }
2435
            break;
2436
         }
2437

2438
         if (j == mark_op && i == old_block)
2439
            nvc_printf("\t $red$<----$$");
2440

2441
         nvc_printf("$$\n");
2442

2443
         if (callback != NULL)
2444
            (*callback)(j, arg);
2445
      }
2446

2447
      if (b->ops.count == 0)
2448
         nvc_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2449
   }
2450

2451
   printf("\n");
2452
   fflush(stdout);
2453

2454
   active_block = old_block;
2455
}
2456
LCOV_EXCL_STOP
2457

2458
static inline bool vtype_eq_internal(const vtype_t *at, const vtype_t *bt)
23,449,593✔
2459
{
2460
   if (at->kind != bt->kind)
23,449,593✔
2461
      return false;
2462

2463
   switch (at->kind) {
6,157,550✔
2464
   case VCODE_TYPE_INT:
4,158,814✔
2465
      return (at->low == bt->low) && (at->high == bt->high);
5,871,328✔
2466
   case VCODE_TYPE_REAL:
76,128✔
2467
      return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
76,189✔
2468
   case VCODE_TYPE_CARRAY:
175,915✔
2469
      return at->size == bt->size && vtype_eq(at->elem, bt->elem);
187,753✔
2470
   case VCODE_TYPE_UARRAY:
123,547✔
2471
      return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
152,297✔
2472
   case VCODE_TYPE_POINTER:
730,695✔
2473
   case VCODE_TYPE_ACCESS:
2474
      return vtype_eq(at->pointed, bt->pointed);
730,695✔
2475
   case VCODE_TYPE_OFFSET:
2476
   case VCODE_TYPE_OPAQUE:
2477
   case VCODE_TYPE_DEBUG_LOCUS:
2478
   case VCODE_TYPE_TRIGGER:
2479
      return true;
2480
   case VCODE_TYPE_RESOLUTION:
133,646✔
2481
   case VCODE_TYPE_CLOSURE:
2482
   case VCODE_TYPE_SIGNAL:
2483
   case VCODE_TYPE_FILE:
2484
      return vtype_eq(at->base, bt->base);
133,646✔
2485
   case VCODE_TYPE_RECORD:
95,534✔
2486
   case VCODE_TYPE_CONTEXT:
2487
      return at->name == bt->name;
95,534✔
2488
   default:
×
2489
      should_not_reach_here();
2490
   }
2491
}
2492

2493
bool vtype_eq(vcode_type_t a, vcode_type_t b)
8,066,616✔
2494
{
2495
   assert(active_unit != NULL);
8,066,616✔
2496

2497
   if (a == b)
8,066,616✔
2498
      return true;
2499
   else if (MASK_CONTEXT(a) == MASK_CONTEXT(b))
1,553,613✔
2500
      return false;   // Guaranteed by vtype_new
2501
   else {
2502
      const vtype_t *at = vcode_type_data(a);
179,201✔
2503
      const vtype_t *bt = vcode_type_data(b);
179,201✔
2504

2505
      return vtype_eq_internal(at, bt);
179,201✔
2506
   }
2507
}
2508

2509
void vcode_dump(void)
×
2510
{
2511
   vcode_dump_with_mark(-1, NULL, NULL);
×
2512
}
×
2513

2514
static vcode_type_t vtype_new(vtype_t *new)
4,123,935✔
2515
{
2516
   const int index = active_unit->types.count - 1;
4,123,935✔
2517

2518
   for (int i = 0; i < index; i++) {
23,782,751✔
2519
      const vtype_t *cmp = vtype_array_nth_ptr(&(active_unit->types), i);
23,270,392✔
2520
      if (vtype_eq_internal(new, cmp)) {
23,270,392✔
2521
         active_unit->types.count--;
3,611,576✔
2522
         return MAKE_HANDLE(active_unit->depth, i);
3,611,576✔
2523
      }
2524
   }
2525

2526
   return MAKE_HANDLE(active_unit->depth, index);
512,359✔
2527
}
2528

2529
vcode_type_t vtype_int(int64_t low, int64_t high)
2,543,023✔
2530
{
2531
   assert(active_unit != NULL);
2,543,023✔
2532

2533
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
2,543,023✔
2534
   n->kind = VCODE_TYPE_INT;
2,543,023✔
2535
   n->low  = low;
2,543,023✔
2536
   n->high = high;
2,543,023✔
2537

2538
   switch (bits_for_range(low, high)) {
2,543,023✔
2539
   case 64:
81,569✔
2540
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
81,569✔
2541
      break;
81,569✔
2542
   case 32:
520,526✔
2543
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
520,526✔
2544
      break;
520,526✔
2545
   case 16:
243✔
2546
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
243✔
2547
      break;
243✔
2548
   case 8:
1,282,788✔
2549
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
1,282,788✔
2550
      break;
1,282,788✔
2551
   case 1:
657,897✔
2552
      n->repr = VCODE_REPR_U1;
657,897✔
2553
      break;
657,897✔
2554
   case 0:
×
2555
      n->repr = VCODE_REPR_I64;    // Null range
×
2556
      break;
×
2557
   default:
×
2558
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2559
   }
2560

2561
   return vtype_new(n);
2,543,023✔
2562
}
2563

2564
vcode_type_t vtype_bool(void)
508,376✔
2565
{
2566
   return vtype_int(0, 1);
508,376✔
2567
}
2568

2569
vcode_type_t vtype_carray(int size, vcode_type_t elem)
98,720✔
2570
{
2571
   assert(active_unit != NULL);
98,720✔
2572

2573
   const vtype_kind_t ekind = vtype_kind(elem);
98,720✔
2574
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
98,720✔
2575
                "array types may not be nested");
2576

2577
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
98,720✔
2578
   memset(n, '\0', sizeof(vtype_t));
98,720✔
2579
   n->kind   = VCODE_TYPE_CARRAY;
98,720✔
2580
   n->elem   = elem;
98,720✔
2581
   n->size   = MAX(size, 0);
98,720✔
2582

2583
   return vtype_new(n);
98,720✔
2584
}
2585

2586
vcode_type_t vtype_find_named_record(ident_t name)
45,803✔
2587
{
2588
   assert(active_unit != NULL);
45,803✔
2589

2590
   for (int i = 0; i < active_unit->types.count; i++) {
427,560✔
2591
      vtype_t *other = &(active_unit->types.items[i]);
409,250✔
2592
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
409,250✔
2593
         return MAKE_HANDLE(active_unit->depth, i);
27,493✔
2594
   }
2595

2596
   return VCODE_INVALID_TYPE;
2597
}
2598

2599
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
18,310✔
2600
                                int nfields)
2601
{
2602
   assert(active_unit != NULL);
18,310✔
2603

2604
   vtype_t *data = NULL;
18,310✔
2605
   vcode_type_t handle = vtype_find_named_record(name);
18,310✔
2606
   if (handle == VCODE_INVALID_TYPE) {
18,310✔
2607
      data = vtype_array_alloc(&(active_unit->types));
9,155✔
2608
      memset(data, '\0', sizeof(vtype_t));
9,155✔
2609
      data->kind = VCODE_TYPE_RECORD;
9,155✔
2610
      data->name = name;
9,155✔
2611

2612
      handle = vtype_new(data);
9,155✔
2613
   }
2614
   else {
2615
      data = vcode_type_data(handle);
9,155✔
2616
      VCODE_ASSERT(data->fields.count == 0,
9,155✔
2617
                    "record type %s already defined", istr(name));
2618
   }
2619

2620
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
18,310✔
2621
   for (int i = 0; i < nfields; i++)
48,948✔
2622
      vcode_type_array_add(&(data->fields), field_types[i]);
30,638✔
2623

2624
   return handle;
18,310✔
2625
}
2626

2627
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem)
119,626✔
2628
{
2629
   assert(active_unit != NULL);
119,626✔
2630

2631
   const vtype_kind_t ekind = vtype_kind(elem);
119,626✔
2632
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
119,626✔
2633
                "array types may not be nested");
2634

2635
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
119,626✔
2636

2637
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
119,626✔
2638
   memset(n, '\0', sizeof(vtype_t));
119,626✔
2639
   n->kind = VCODE_TYPE_UARRAY;
119,626✔
2640
   n->elem = elem;
119,626✔
2641
   n->dims = ndim;
119,626✔
2642

2643
   return vtype_new(n);
119,626✔
2644
}
2645

2646
vcode_type_t vtype_pointer(vcode_type_t to)
317,267✔
2647
{
2648
   assert(active_unit != NULL);
317,267✔
2649

2650
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
317,267✔
2651
   n->kind    = VCODE_TYPE_POINTER;
317,267✔
2652
   n->pointed = to;
317,267✔
2653

2654
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
317,267✔
2655
                "cannot get pointer to carray type");
2656

2657
   return vtype_new(n);
317,267✔
2658
}
2659

2660
vcode_type_t vtype_access(vcode_type_t to)
10,708✔
2661
{
2662
   assert(active_unit != NULL);
10,708✔
2663

2664
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
10,708✔
2665
   n->kind    = VCODE_TYPE_ACCESS;
10,708✔
2666
   n->pointed = to;
10,708✔
2667

2668
   return vtype_new(n);
10,708✔
2669
}
2670

2671
vcode_type_t vtype_signal(vcode_type_t base)
69,146✔
2672
{
2673
   assert(active_unit != NULL);
69,146✔
2674

2675
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
69,146✔
2676
   n->kind = VCODE_TYPE_SIGNAL;
69,146✔
2677
   n->base = base;
69,146✔
2678

2679
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
69,146✔
2680

2681
   return vtype_new(n);
69,146✔
2682
}
2683

2684
vcode_type_t vtype_resolution(vcode_type_t base)
20,026✔
2685
{
2686
   assert(active_unit != NULL);
20,026✔
2687

2688
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
20,026✔
2689
   n->kind = VCODE_TYPE_RESOLUTION;
20,026✔
2690
   n->base = base;
20,026✔
2691

2692
   return vtype_new(n);
20,026✔
2693
}
2694

2695
vcode_type_t vtype_closure(vcode_type_t result)
14,528✔
2696
{
2697
   assert(active_unit != NULL);
14,528✔
2698

2699
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
14,528✔
2700
   n->kind = VCODE_TYPE_CLOSURE;
14,528✔
2701
   n->base = result;
14,528✔
2702

2703
   return vtype_new(n);
14,528✔
2704
}
2705

2706
vcode_type_t vtype_context(ident_t name)
87,507✔
2707
{
2708
   assert(active_unit != NULL);
87,507✔
2709
   assert(name != NULL);
87,507✔
2710

2711
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
87,507✔
2712
   n->kind = VCODE_TYPE_CONTEXT;
87,507✔
2713
   n->name = name;
87,507✔
2714

2715
   return vtype_new(n);
87,507✔
2716
}
2717

2718
vcode_type_t vtype_file(vcode_type_t base)
2,698✔
2719
{
2720
   assert(active_unit != NULL);
2,698✔
2721

2722
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
2,698✔
2723
   n->kind = VCODE_TYPE_FILE;
2,698✔
2724
   n->base = base;
2,698✔
2725

2726
   return vtype_new(n);
2,698✔
2727
}
2728

2729
vcode_type_t vtype_offset(void)
494,701✔
2730
{
2731
   assert(active_unit != NULL);
494,701✔
2732

2733
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
494,701✔
2734
   n->kind = VCODE_TYPE_OFFSET;
494,701✔
2735
   n->low  = INT64_MIN;
494,701✔
2736
   n->high = INT64_MAX;
494,701✔
2737
   n->repr = VCODE_REPR_I64;
494,701✔
2738

2739
   return vtype_new(n);
494,701✔
2740
}
2741

2742
vcode_type_t vtype_time(void)
19,680✔
2743
{
2744
   return vtype_int(INT64_MIN, INT64_MAX);
19,680✔
2745
}
2746

2747
vcode_type_t vtype_char(void)
24,555✔
2748
{
2749
   return vtype_int(0, 255);
24,555✔
2750
}
2751

2752
vcode_type_t vtype_opaque(void)
4,557✔
2753
{
2754
   assert(active_unit != NULL);
4,557✔
2755

2756
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
4,557✔
2757
   n->kind = VCODE_TYPE_OPAQUE;
4,557✔
2758

2759
   return vtype_new(n);
4,557✔
2760
}
2761

2762
vcode_type_t vtype_debug_locus(void)
246,400✔
2763
{
2764
   assert(active_unit != NULL);
246,400✔
2765

2766
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
246,400✔
2767
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
246,400✔
2768

2769
   return vtype_new(n);
246,400✔
2770
}
2771

2772
vcode_type_t vtype_trigger(void)
691✔
2773
{
2774
   assert(active_unit != NULL);
691✔
2775

2776
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
691✔
2777
   n->kind = VCODE_TYPE_TRIGGER;
691✔
2778

2779
   return vtype_new(n);
691✔
2780
}
2781

2782
vcode_type_t vtype_real(double low, double high)
85,182✔
2783
{
2784
   assert(active_unit != NULL);
85,182✔
2785

2786
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
85,182✔
2787
   n->kind  = VCODE_TYPE_REAL;
85,182✔
2788
   n->rlow  = low;
85,182✔
2789
   n->rhigh = high;
85,182✔
2790

2791
   return vtype_new(n);
85,182✔
2792
}
2793

2794
vtype_kind_t vtype_kind(vcode_type_t type)
6,257,581✔
2795
{
2796
   vtype_t *vt = vcode_type_data(type);
6,257,581✔
2797
   return vt->kind;
6,257,581✔
2798
}
2799

2800
vtype_repr_t vtype_repr(vcode_type_t type)
59,927✔
2801
{
2802
   vtype_t *vt = vcode_type_data(type);
59,927✔
2803
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
59,927✔
2804
   return vt->repr;
59,927✔
2805
}
2806

2807
vcode_type_t vtype_elem(vcode_type_t type)
217,197✔
2808
{
2809
   vtype_t *vt = vcode_type_data(type);
217,197✔
2810
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
217,197✔
2811
   return vt->elem;
217,197✔
2812
}
2813

2814
vcode_type_t vtype_base(vcode_type_t type)
98,744✔
2815
{
2816
   vtype_t *vt = vcode_type_data(type);
98,744✔
2817
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
98,744✔
2818
          || vt->kind == VCODE_TYPE_RESOLUTION
2819
          || vt->kind == VCODE_TYPE_CLOSURE);
2820
   return vt->base;
98,744✔
2821
}
2822

2823
unsigned vtype_dims(vcode_type_t type)
63,519✔
2824
{
2825
   vtype_t *vt = vcode_type_data(type);
63,519✔
2826
   assert(vt->kind == VCODE_TYPE_UARRAY);
63,519✔
2827
   return vt->dims;
63,519✔
2828
}
2829

2830
unsigned vtype_size(vcode_type_t type)
87,384✔
2831
{
2832
   vtype_t *vt = vcode_type_data(type);
87,384✔
2833
   assert(vt->kind == VCODE_TYPE_CARRAY);
87,384✔
2834
   return vt->size;
87,384✔
2835
}
2836

2837
int vtype_fields(vcode_type_t type)
12,505✔
2838
{
2839
   vtype_t *vt = vcode_type_data(type);
12,505✔
2840
   assert(vt->kind == VCODE_TYPE_RECORD);
12,505✔
2841
   return vt->fields.count;
12,505✔
2842
}
2843

2844
vcode_type_t vtype_field(vcode_type_t type, int field)
49,881✔
2845
{
2846
   vtype_t *vt = vcode_type_data(type);
49,881✔
2847
   assert(vt->kind == VCODE_TYPE_RECORD);
49,881✔
2848
   return vcode_type_array_nth(&(vt->fields), field);
49,881✔
2849
}
2850

2851
ident_t vtype_name(vcode_type_t type)
28,009✔
2852
{
2853
   vtype_t *vt = vcode_type_data(type);
28,009✔
2854
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
28,009✔
2855
   return vt->name;
28,009✔
2856
}
2857

2858
vcode_type_t vtype_pointed(vcode_type_t type)
509,708✔
2859
{
2860
   vtype_t *vt = vcode_type_data(type);
509,708✔
2861
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
509,708✔
2862
   return vt->pointed;
509,708✔
2863
}
2864

2865
int64_t vtype_low(vcode_type_t type)
124,571✔
2866
{
2867
   vtype_t *vt = vcode_type_data(type);
124,571✔
2868
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
124,571✔
2869
   return vt->low;
124,571✔
2870
}
2871

2872
int64_t vtype_high(vcode_type_t type)
125,512✔
2873
{
2874
   vtype_t *vt = vcode_type_data(type);
125,512✔
2875
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
125,512✔
2876
   return vt->high;
125,512✔
2877
}
2878

2879
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
2,678✔
2880
{
2881
   return vtype_kind(type) == VCODE_TYPE_POINTER
2,678✔
2882
      && vtype_kind(vtype_pointed(type)) == to;
2,678✔
2883
}
2884

2885
bool vtype_is_scalar(vcode_type_t type)
650,082✔
2886
{
2887
   const vtype_kind_t kind = vtype_kind(type);
650,082✔
2888
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
650,082✔
2889
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
258,713✔
2890
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2891
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2892
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER
2893
      || kind == VCODE_TYPE_RESOLUTION;
650,082✔
2894
}
2895

2896
bool vtype_is_numeric(vcode_type_t type)
25,744✔
2897
{
2898
   const vtype_kind_t kind = vtype_kind(type);
25,744✔
2899
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
25,744✔
2900
      || kind == VCODE_TYPE_REAL;
25,744✔
2901
}
2902

2903
bool vtype_is_integral(vcode_type_t type)
1,222✔
2904
{
2905
   const vtype_kind_t kind = vtype_kind(type);
1,222✔
2906
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET;
1,222✔
2907
}
2908

2909
bool vtype_is_composite(vcode_type_t type)
54,853✔
2910
{
2911
   const vtype_kind_t kind = vtype_kind(type);
54,853✔
2912
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
54,853✔
2913
}
2914

2915
bool vtype_is_signal(vcode_type_t type)
216,537✔
2916
{
2917
   vtype_t *vt = vcode_type_data(type);
385,792✔
2918
   switch (vt->kind) {
385,792✔
2919
   case VCODE_TYPE_SIGNAL:
2920
      return true;
2921
   case VCODE_TYPE_POINTER:
100,480✔
2922
      return vtype_is_signal(vt->pointed);
100,480✔
2923
   case VCODE_TYPE_RECORD:
2924
      for (int i = 0; i < vt->fields.count; i++) {
49,188✔
2925
         if (vtype_is_signal(vt->fields.items[i]))
38,713✔
2926
            return true;
2927
      }
2928
      return false;
2929
   case VCODE_TYPE_UARRAY:
68,775✔
2930
   case VCODE_TYPE_CARRAY:
2931
      return vtype_is_signal(vt->elem);
68,775✔
2932
   default:
166,365✔
2933
      return false;
166,365✔
2934
   }
2935
}
2936

2937
int vtype_repr_bits(vtype_repr_t repr)
×
2938
{
2939
   switch (repr) {
×
2940
   case VCODE_REPR_U1: return 1;
2941
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2942
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2943
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2944
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2945
   default: return -1;
2946
   }
2947
}
2948

2949
bool vtype_repr_signed(vtype_repr_t repr)
×
2950
{
2951
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
×
2952
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
×
2953
}
2954

2955
static int64_t vtype_repr_low(vtype_repr_t repr)
19,385✔
2956
{
2957
   switch (repr) {
19,385✔
2958
   case VCODE_REPR_U1:
2959
   case VCODE_REPR_U8:
2960
   case VCODE_REPR_U16:
2961
   case VCODE_REPR_U32:
2962
   case VCODE_REPR_U64: return 0;
2963
   case VCODE_REPR_I8:  return INT8_MIN;
2964
   case VCODE_REPR_I16: return INT16_MIN;
2965
   case VCODE_REPR_I32: return INT32_MIN;
2966
   case VCODE_REPR_I64: return INT64_MIN;
2967
   default:             return 0;
2968
   }
2969
}
2970

2971
static uint64_t vtype_repr_high(vtype_repr_t repr)
19,385✔
2972
{
2973
   switch (repr) {
19,385✔
2974
   case VCODE_REPR_U1:  return 1;
2975
   case VCODE_REPR_U8:  return UINT8_MAX;
2976
   case VCODE_REPR_U16: return UINT16_MAX;
2977
   case VCODE_REPR_U32: return UINT32_MAX;
2978
   case VCODE_REPR_U64: return UINT64_MAX;
2979
   case VCODE_REPR_I8:  return INT8_MAX;
2980
   case VCODE_REPR_I16: return INT16_MAX;
2981
   case VCODE_REPR_I32: return INT32_MAX;
2982
   case VCODE_REPR_I64: return INT64_MAX;
2983
   default:             return 0;
2984
   }
2985
}
2986

2987
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
19,385✔
2988
{
2989
   int64_t clamp_low = vtype_repr_low(repr);
19,385✔
2990
   uint64_t clamp_high = vtype_repr_high(repr);
19,385✔
2991

2992
   if (*low >= clamp_low && *high <= clamp_high)
19,385✔
2993
      return true;
2994
   else {
2995
      *low = MAX(clamp_low, *low);
9,494✔
2996
      *high = MIN(clamp_high, *high);
9,494✔
2997
      return false;
9,494✔
2998
   }
2999
}
3000

3001
static vcode_stamp_t vstamp_new(const vstamp_t *s)
1,145,664✔
3002
{
3003
   assert(active_unit != NULL);
1,145,664✔
3004

3005
   for (int i = 0; i < active_unit->stamps.count; i++) {
11,147,690✔
3006
      vstamp_t *cmp = &(active_unit->stamps.items[i]);
10,639,089✔
3007
      if (cmp->kind == s->kind && memcmp(&cmp->u, &s->u, sizeof(s->u)) == 0)
10,639,089✔
3008
         return MAKE_HANDLE(active_unit->depth, i);
637,063✔
3009
   }
3010

3011
   vstamp_t *new = vstamp_array_alloc(&(active_unit->stamps));
508,601✔
3012
   *new = *s;
508,601✔
3013

3014
   return MAKE_HANDLE(active_unit->depth, active_unit->stamps.count - 1);
508,601✔
3015
}
3016

3017
vcode_stamp_t vstamp_int(int64_t low, int64_t high)
1,089,874✔
3018
{
3019
   const vstamp_t s = {
1,089,874✔
3020
      .kind = VCODE_STAMP_INT,
3021
      .u = { .intg = { .low = low, .high = high } },
3022
   };
3023
   return vstamp_new(&s);
1,089,874✔
3024
}
3025

3026
vcode_stamp_t vstamp_real(double low, double high)
55,790✔
3027
{
3028
   const vstamp_t s = {
55,790✔
3029
      .kind = VCODE_STAMP_REAL,
3030
      .u = { .real = { .low = low, .high = high } },
3031
   };
3032
   return vstamp_new(&s);
55,790✔
3033
}
3034

3035
vcode_stamp_t vstamp_char(void)
8,709✔
3036
{
3037
   return vstamp_int(0, 255);
8,709✔
3038
}
3039

3040
int vcode_count_params(void)
28,802✔
3041
{
3042
   assert(active_unit != NULL);
28,802✔
3043
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
28,802✔
3044
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3045
          || active_unit->kind == VCODE_UNIT_PROPERTY
3046
          || active_unit->kind == VCODE_UNIT_PROTECTED
3047
          || active_unit->kind == VCODE_UNIT_PROCESS);
3048

3049
   return active_unit->params.count;
28,802✔
3050
}
3051

3052
vcode_type_t vcode_param_type(int param)
43,605✔
3053
{
3054
   assert(active_unit != NULL);
43,605✔
3055
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
43,605✔
3056
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3057
          || active_unit->kind == VCODE_UNIT_PROPERTY
3058
          || active_unit->kind == VCODE_UNIT_PROTECTED
3059
          || active_unit->kind == VCODE_UNIT_PROCESS);
3060
   assert(param < active_unit->params.count);
43,605✔
3061

3062
   return active_unit->params.items[param].type;
43,605✔
3063
}
3064

3065
ident_t vcode_param_name(int param)
43,605✔
3066
{
3067
   assert(active_unit != NULL);
43,605✔
3068
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
43,605✔
3069
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3070
          || active_unit->kind == VCODE_UNIT_PROPERTY
3071
          || active_unit->kind == VCODE_UNIT_PROTECTED
3072
          || active_unit->kind == VCODE_UNIT_PROCESS);
3073
   assert(param < active_unit->params.count);
43,605✔
3074

3075
   return active_unit->params.items[param].name;
43,605✔
3076
}
3077

3078
vcode_reg_t vcode_param_reg(int param)
43,605✔
3079
{
3080
   assert(active_unit != NULL);
43,605✔
3081
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
43,605✔
3082
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3083
          || active_unit->kind == VCODE_UNIT_PROPERTY
3084
          || active_unit->kind == VCODE_UNIT_PROTECTED
3085
          || active_unit->kind == VCODE_UNIT_PROCESS);
3086
   assert(param < active_unit->params.count);
43,605✔
3087

3088
   return active_unit->params.items[param].reg;
43,605✔
3089
}
3090

3091
vcode_block_t emit_block(void)
205,352✔
3092
{
3093
   assert(active_unit != NULL);
205,352✔
3094

3095
   vcode_block_t bnum = active_unit->blocks.count;
205,352✔
3096

3097
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
205,352✔
3098
   memset(bptr, '\0', sizeof(block_t));
205,352✔
3099

3100
   if (active_block != VCODE_INVALID_BLOCK)
205,352✔
3101
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
126,865✔
3102
   else
3103
      bptr->last_loc = LOC_INVALID;
78,487✔
3104

3105
   return bnum;
205,352✔
3106
}
3107

3108
void vcode_select_unit(vcode_unit_t unit)
268,205✔
3109
{
3110
   active_unit  = unit;
268,205✔
3111
   active_block = VCODE_INVALID_BLOCK;
268,205✔
3112
}
268,205✔
3113

3114
void vcode_select_block(vcode_block_t block)
448,018✔
3115
{
3116
   assert(active_unit != NULL);
448,018✔
3117
   active_block = block;
448,018✔
3118
}
448,018✔
3119

3120
vcode_block_t vcode_active_block(void)
2,039✔
3121
{
3122
   assert(active_unit != NULL);
2,039✔
3123
   assert(active_block != -1);
2,039✔
3124
   return active_block;
2,039✔
3125
}
3126

3127
const loc_t *vcode_last_loc(void)
2,234,419✔
3128
{
3129
   return &(vcode_block_data()->last_loc);
2,234,419✔
3130
}
3131

3132
vcode_unit_t vcode_active_unit(void)
925✔
3133
{
3134
   assert(active_unit != NULL);
925✔
3135
   return active_unit;
925✔
3136
}
3137

3138
ident_t vcode_unit_name(vcode_unit_t vu)
225,013✔
3139
{
3140
   assert(vu != NULL);
225,013✔
3141
   return vu->name;
225,013✔
3142
}
3143

3144
bool vcode_unit_has_undefined(vcode_unit_t vu)
14,377✔
3145
{
3146
   assert(vu != NULL);
14,377✔
3147
   return !!(vu->flags & UNIT_UNDEFINED);
14,377✔
3148
}
3149

3150
int vcode_unit_depth(vcode_unit_t vu)
×
3151
{
3152
   assert(vu != NULL);
×
3153
   return vu->depth;
×
3154
}
3155

3156
void vcode_set_result(vcode_type_t type)
27,323✔
3157
{
3158
   assert(active_unit != NULL);
27,323✔
3159
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
27,323✔
3160
          || active_unit->kind == VCODE_UNIT_THUNK);
3161

3162
   active_unit->result = type;
27,323✔
3163
}
27,323✔
3164

3165
vcode_type_t vcode_unit_result(vcode_unit_t vu)
30,785✔
3166
{
3167
   assert(vu != NULL);
30,785✔
3168
   assert(vu->kind == VCODE_UNIT_FUNCTION || vu->kind == VCODE_UNIT_THUNK);
30,785✔
3169
   return vu->result;
30,785✔
3170
}
3171

3172
vunit_kind_t vcode_unit_kind(vcode_unit_t vu)
197,982✔
3173
{
3174
   assert(vu != NULL);
197,982✔
3175
   return vu->kind;
197,982✔
3176
}
3177

3178
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
85,952✔
3179
{
3180
   assert(vu != NULL);
85,952✔
3181
   return vu->context;
85,952✔
3182
}
3183

3184
object_t *vcode_unit_object(vcode_unit_t vu)
115,748✔
3185
{
3186
   assert(vu != NULL);
115,748✔
3187
   return vu->object;
115,748✔
3188
}
3189

3190
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
92,880✔
3191
{
3192
   int hops = 0;
92,880✔
3193
   for (; (unit = unit->context); hops++)
221,644✔
3194
      ;
3195
   return hops;
92,880✔
3196
}
3197

3198
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
39,848✔
3199
{
3200
   assert(context->kind != VCODE_UNIT_THUNK);
39,848✔
3201

3202
   child->next = NULL;
39,848✔
3203
   if (context->children == NULL)
39,848✔
3204
      context->children = child;
18,701✔
3205
   else {
3206
      vcode_unit_t it;
3207
      for (it = context->children; it->next != NULL; it = it->next)
92,310✔
3208
         ;
3209
      it->next = child;
21,147✔
3210
   }
3211
}
39,848✔
3212

3213
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
16,423✔
3214
{
3215
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
16,423✔
3216
   vu->kind     = VCODE_UNIT_FUNCTION;
16,423✔
3217
   vu->name     = name;
16,423✔
3218
   vu->context  = context;
16,423✔
3219
   vu->result   = VCODE_INVALID_TYPE;
16,423✔
3220
   vu->depth    = vcode_unit_calc_depth(vu);
16,423✔
3221
   vu->object   = obj;
16,423✔
3222

3223
   vcode_add_child(context, vu);
16,423✔
3224

3225
   vcode_select_unit(vu);
16,423✔
3226
   vcode_select_block(emit_block());
16,423✔
3227
   emit_debug_info(&(obj->loc));
16,423✔
3228

3229
   return vu;
16,423✔
3230
}
3231

3232
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
281✔
3233
{
3234
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
281✔
3235
   vu->kind     = VCODE_UNIT_PROCEDURE;
281✔
3236
   vu->name     = name;
281✔
3237
   vu->context  = context;
281✔
3238
   vu->result   = VCODE_INVALID_TYPE;
281✔
3239
   vu->depth    = vcode_unit_calc_depth(vu);
281✔
3240
   vu->object   = obj;
281✔
3241

3242
   vcode_add_child(context, vu);
281✔
3243

3244
   vcode_select_unit(vu);
281✔
3245
   vcode_select_block(emit_block());
281✔
3246
   emit_debug_info(&(obj->loc));
281✔
3247

3248
   return vu;
281✔
3249
}
3250

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

3261
   vcode_add_child(context, vu);
10,738✔
3262

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

3267
   return vu;
10,738✔
3268
}
3269

3270
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
17,057✔
3271
{
3272
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
17,057✔
3273

3274
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
17,057✔
3275
   vu->kind     = VCODE_UNIT_INSTANCE;
17,057✔
3276
   vu->name     = name;
17,057✔
3277
   vu->context  = context;
17,057✔
3278
   vu->depth    = vcode_unit_calc_depth(vu);
17,057✔
3279
   vu->result   = VCODE_INVALID_TYPE;
17,057✔
3280
   vu->object   = obj;
17,057✔
3281

3282
   if (context != NULL)
17,057✔
3283
      vcode_add_child(context, vu);
10,346✔
3284

3285
   vcode_select_unit(vu);
17,057✔
3286
   vcode_select_block(emit_block());
17,057✔
3287
   emit_debug_info(&(obj->loc));
17,057✔
3288

3289
   return vu;
17,057✔
3290
}
3291

3292
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
18,235✔
3293
{
3294
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
18,235✔
3295
   vu->kind     = VCODE_UNIT_PACKAGE;
18,235✔
3296
   vu->name     = name;
18,235✔
3297
   vu->context  = context;
18,235✔
3298
   vu->depth    = vcode_unit_calc_depth(vu);
18,235✔
3299
   vu->result   = VCODE_INVALID_TYPE;
18,235✔
3300
   vu->object   = obj;
18,235✔
3301

3302
   if (context != NULL)
18,235✔
3303
      vcode_add_child(context, vu);
330✔
3304

3305
   vcode_select_unit(vu);
18,235✔
3306
   vcode_select_block(emit_block());
18,235✔
3307
   emit_debug_info(&(obj->loc));
18,235✔
3308

3309
   return vu;
18,235✔
3310
}
3311

3312
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
1,032✔
3313
{
3314
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
1,032✔
3315
   vu->kind     = VCODE_UNIT_PROTECTED;
1,032✔
3316
   vu->name     = name;
1,032✔
3317
   vu->context  = context;
1,032✔
3318
   vu->depth    = vcode_unit_calc_depth(vu);
1,032✔
3319
   vu->result   = VCODE_INVALID_TYPE;
1,032✔
3320
   vu->object   = obj;
1,032✔
3321

3322
   if (context != NULL)
1,032✔
3323
      vcode_add_child(context, vu);
1,032✔
3324

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

3329
   return vu;
1,032✔
3330
}
3331

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

3342
   if (context != NULL)
328✔
3343
      vcode_add_child(context, vu);
328✔
3344

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

3349
   return vu;
328✔
3350
}
3351

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

3363
   if (context != NULL)
14,393✔
3364
      vcode_add_child(context, vu);
370✔
3365

3366
   vcode_select_unit(vu);
14,393✔
3367
   vcode_select_block(emit_block());
14,393✔
3368

3369
   return vu;
14,393✔
3370
}
3371

3372
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
19,849✔
3373
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3374
                 vcode_reg_t hint_right)
3375
{
3376
   int64_t value_const;
19,849✔
3377
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
19,849✔
3378
      emit_comment("Always true assertion on r%d", value);
64✔
3379
      return;
64✔
3380
   }
3381

3382
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
19,785✔
3383
   vcode_add_arg(op, value);
19,785✔
3384
   vcode_add_arg(op, severity);
19,785✔
3385
   vcode_add_arg(op, message);
19,785✔
3386
   vcode_add_arg(op, length);
19,785✔
3387
   vcode_add_arg(op, locus);
19,785✔
3388

3389
   if (hint_left != VCODE_INVALID_REG) {
19,785✔
3390
      vcode_add_arg(op, hint_left);
8,192✔
3391
      vcode_add_arg(op, hint_right);
8,192✔
3392

3393
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
8,192✔
3394
                   "left hint must be scalar");
3395
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
8,192✔
3396
                   "right hint must be scalar");
3397
   }
3398

3399
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
19,785✔
3400
                "value parameter to assert is not bool");
3401
   VCODE_ASSERT(message == VCODE_INVALID_REG
19,785✔
3402
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3403
                "message parameter to assert is not a pointer");
3404
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
19,785✔
3405
                "value parameter to assert is not bool");
3406
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
19,785✔
3407
                "locus argument to report must be a debug locus");
3408
}
3409

3410
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,835✔
3411
                 vcode_reg_t locus)
3412
{
3413
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,835✔
3414
   vcode_add_arg(op, severity);
2,835✔
3415
   vcode_add_arg(op, message);
2,835✔
3416
   vcode_add_arg(op, length);
2,835✔
3417
   vcode_add_arg(op, locus);
2,835✔
3418

3419
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,835✔
3420
                "message parameter to report is not a pointer");
3421
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,835✔
3422
                "message parameter to report is not a character pointer");
3423
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,835✔
3424
                "locus argument to report must be a debug locus");
3425
}
2,835✔
3426

3427
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
47,293✔
3428
{
3429
   if (lhs == rhs) {
47,293✔
3430
      if (cmp == VCODE_CMP_EQ)
537✔
3431
         return emit_const(vtype_bool(), 1);
325✔
3432
      else if (cmp == VCODE_CMP_NEQ)
212✔
3433
         return emit_const(vtype_bool(), 0);
×
3434
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
212✔
3435
         return emit_const(vtype_bool(), 1);
×
3436
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
212✔
3437
         return emit_const(vtype_bool(), 0);
212✔
3438
   }
3439

3440
   int64_t lconst, rconst;
46,756✔
3441
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
46,756✔
3442
      switch (cmp) {
432✔
3443
      case VCODE_CMP_EQ:
397✔
3444
         return emit_const(vtype_bool(), lconst == rconst);
397✔
3445
      case VCODE_CMP_NEQ:
4✔
3446
         return emit_const(vtype_bool(), lconst != rconst);
4✔
3447
      case VCODE_CMP_LT:
15✔
3448
         return emit_const(vtype_bool(), lconst < rconst);
15✔
3449
      case VCODE_CMP_GT:
16✔
3450
         return emit_const(vtype_bool(), lconst > rconst);
16✔
3451
      case VCODE_CMP_LEQ:
×
3452
         return emit_const(vtype_bool(), lconst <= rconst);
×
3453
      case VCODE_CMP_GEQ:
×
3454
         return emit_const(vtype_bool(), lconst >= rconst);
×
3455
      default:
×
3456
         fatal_trace("cannot fold comparison %d", cmp);
3457
      }
3458
   }
3459

3460
   // Reuse any previous operation in this block with the same arguments
3461
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
892,068✔
3462
      if (other->args.count == 2 && other->args.items[0] == lhs
30,623✔
3463
          && other->args.items[1] == rhs && other->cmp == cmp)
2,886✔
3464
         return other->result;
256✔
3465
   }
3466

3467
   op_t *op = vcode_add_op(VCODE_OP_CMP);
46,068✔
3468
   vcode_add_arg(op, lhs);
46,068✔
3469
   vcode_add_arg(op, rhs);
46,068✔
3470
   op->cmp    = cmp;
46,068✔
3471
   op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP);
46,068✔
3472

3473
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
46,068✔
3474
                "arguments to cmp are not the same type");
3475

3476
   return op->result;
46,068✔
3477
}
3478

3479
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_stamp_t stamp,
46,793✔
3480
                       const vcode_reg_t *args, int nargs)
3481
{
3482
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
46,793✔
3483
   o->func = func;
46,793✔
3484
   o->type = type;
46,793✔
3485
   for (int i = 0; i < nargs; i++)
165,602✔
3486
      vcode_add_arg(o, args[i]);
118,809✔
3487

3488
   for (int i = 0; i < nargs; i++)
165,602✔
3489
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
118,809✔
3490
                   "invalid argument to function");
3491

3492
   if (type == VCODE_INVALID_TYPE)
46,793✔
3493
      return (o->result = VCODE_INVALID_REG);
7,955✔
3494
   else
3495
      return (o->result = vcode_add_reg(type, stamp));
38,838✔
3496
}
3497

3498
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
1,163✔
3499
                vcode_block_t resume_bb)
3500
{
3501
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
1,163✔
3502
   o->func = func;
1,163✔
3503
   for (int i = 0; i < nargs; i++)
3,869✔
3504
      vcode_add_arg(o, args[i]);
2,706✔
3505

3506
   vcode_block_array_add(&(o->targets), resume_bb);
1,163✔
3507

3508
   for (int i = 0; i < nargs; i++)
3,869✔
3509
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,706✔
3510
                   "invalid argument to procedure");
3511

3512
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
1,163✔
3513
                "first argument to VHDL procedure must be context pointer");
3514
}
1,163✔
3515

3516
vcode_reg_t emit_alloc(vcode_type_t type, vcode_stamp_t stamp,
10,691✔
3517
                       vcode_reg_t count)
3518
{
3519
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
10,691✔
3520
   op->type = type;
10,691✔
3521
   vcode_add_arg(op, count);
10,691✔
3522

3523
   const vtype_kind_t tkind = vtype_kind(type);
10,691✔
3524
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
10,691✔
3525
                "alloca element type cannot be array");
3526
   VCODE_ASSERT(count != VCODE_INVALID_REG,
10,691✔
3527
                "alloca must have valid count argument");
3528

3529
   return (op->result = vcode_add_reg(vtype_pointer(type), stamp));
10,691✔
3530
}
3531

3532
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
2,656,974✔
3533
{
3534
   // Reuse any previous constant in this block with the same type and value
3535
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
63,626,308✔
3536
      if (other->value == value && vtype_eq(type, other->type))
21,685,637✔
3537
         return other->result;
1,986,319✔
3538
   }
3539

3540
   op_t *op = vcode_add_op(VCODE_OP_CONST);
670,655✔
3541
   op->value  = value;
670,655✔
3542
   op->type   = type;
670,655✔
3543
   op->result = vcode_add_reg(type, vstamp_int(value, value));
670,655✔
3544

3545
   vtype_kind_t type_kind = vtype_kind(type);
670,655✔
3546
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
670,655✔
3547
                "constant must have integer or offset type");
3548

3549
   return op->result;
3550
}
3551

3552
vcode_reg_t emit_const_real(vcode_type_t type, double value)
89,616✔
3553
{
3554
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
2,784,304✔
3555
      if (other->real == value && other->type == type)
1,179,408✔
3556
         return other->result;
35,115✔
3557
   }
3558

3559
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
54,501✔
3560
   op->real   = value;
54,501✔
3561
   op->type   = type;
54,501✔
3562
   op->result = vcode_add_reg(op->type, vstamp_real(value, value));
54,501✔
3563

3564
   return op->result;
54,501✔
3565
}
3566

3567
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
62,177✔
3568
{
3569
   vtype_kind_t kind = vtype_kind(type);
62,177✔
3570

3571
   // Reuse any previous operation in this block with the same arguments
3572
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
3,434,626✔
3573
      if (other->args.count != num)
240,483✔
3574
         continue;
142,354✔
3575
      else if (!vtype_eq(vcode_reg_type(other->result), type))
98,129✔
3576
         continue;
4,138✔
3577

3578
      bool match = true;
3579
      for (int i = 0; match && i < num; i++) {
712,180✔
3580
         if (other->args.items[i] != values[i])
618,189✔
3581
            match = false;
84,240✔
3582
      }
3583

3584
      if (match) return other->result;
93,991✔
3585
   }
3586

3587
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
52,426✔
3588
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
52,426✔
3589

3590
   for (int i = 0; i < num; i++)
3,065,315✔
3591
      vcode_add_arg(op, values[i]);
3,012,889✔
3592

3593
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
52,426✔
3594
                "constant array must have constrained array type");
3595
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
52,426✔
3596
                vtype_size(type), num);
3597

3598
#ifdef DEBUG
3599
   vcode_type_t elem = vtype_elem(type);
52,426✔
3600
   for (int i = 0; i < num; i++) {
3,065,315✔
3601
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
3,012,889✔
3602
                   "wrong element type for item %d", i);
3603
      vcode_assert_const(values[i], "array");
3,012,889✔
3604
   }
3605
#endif
3606

3607
   return op->result;
52,426✔
3608
}
3609

3610
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
657✔
3611
{
3612
   // Reuse any previous operation in this block with the same arguments
3613
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
12,218✔
3614
      if (other->args.items[0] == value && other->value == rep)
563✔
3615
         return other->result;
237✔
3616
   }
3617

3618
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
420✔
3619
   op->value = rep;
420✔
3620
   vcode_add_arg(op, value);
420✔
3621

3622
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
420✔
3623
                "constant array must have constrained array type");
3624
   VCODE_ASSERT(rep >= 0, "repeat count must be non-negative");
420✔
3625

3626
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
420✔
3627

3628
   return (op->result = vcode_add_reg(type, vcode_reg_data(value)->stamp));
420✔
3629
}
3630

3631
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
3,622✔
3632
{
3633
   // Reuse any previous constant in this block with the same type and value
3634
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
56,930✔
3635
      if (other->args.count == num && vtype_eq(type, other->type)) {
2,006✔
3636
         bool same_regs = true;
3637
         for (int i = 0; same_regs && i < num; i++)
3,479✔
3638
            same_regs = other->args.items[i] == values[i];
2,015✔
3639

3640
         if (same_regs)
1,464✔
3641
            return other->result;
250✔
3642
      }
3643
   }
3644

3645
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
3,372✔
3646
   op->type   = type;
3,372✔
3647
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
3,372✔
3648

3649
   for (int i = 0; i < num; i++)
11,927✔
3650
      vcode_add_arg(op, values[i]);
8,555✔
3651

3652
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
3,372✔
3653
                "constant record must have record type");
3654

3655
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
3,372✔
3656
                vtype_fields(type), num);
3657

3658
#ifdef DEBUG
3659
   for (int i = 0; i < num; i++) {
11,927✔
3660
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
8,555✔
3661
                   "wrong type for field %d", i);
3662
      vcode_assert_const(values[i], "record");
8,555✔
3663
   }
3664
#endif
3665

3666
   return op->result;
3,372✔
3667
}
3668

3669
vcode_reg_t emit_address_of(vcode_reg_t value)
64,620✔
3670
{
3671
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
3,556,351✔
3672
      if (other->args.items[0] == value)
242,094✔
3673
         return other->result;
9,767✔
3674
   }
3675

3676
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
54,853✔
3677
   vcode_add_arg(op, value);
54,853✔
3678

3679
   vcode_type_t vtype = vcode_reg_type(value);
54,853✔
3680

3681
   VCODE_ASSERT(vtype_is_composite(vtype),
54,853✔
3682
                "address of argument must be record or array");
3683

3684
   if (vtype_kind(vtype) == VCODE_TYPE_CARRAY) {
54,853✔
3685
      vcode_type_t elem = vtype_elem(vtype);
52,180✔
3686
      vcode_stamp_t stamp = vcode_reg_stamp(value);
52,180✔
3687
      return (op->result = vcode_add_reg(vtype_pointer(elem), stamp));
52,180✔
3688
   }
3689
   else {
3690
      vcode_stamp_t stamp = VCODE_INVALID_STAMP;
2,673✔
3691
      return (op->result = vcode_add_reg(vtype_pointer(vtype), stamp));
2,673✔
3692
   }
3693
}
3694

3695
void emit_wait(vcode_block_t target)
17,862✔
3696
{
3697
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
17,862✔
3698
   vcode_add_target(op, target);
17,862✔
3699
}
17,862✔
3700

3701
void emit_jump(vcode_block_t target)
55,016✔
3702
{
3703
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
55,016✔
3704
   vcode_add_target(op, target);
55,016✔
3705

3706
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
55,016✔
3707
}
55,016✔
3708

3709
vcode_var_t emit_var(vcode_type_t type, vcode_stamp_t stamp, ident_t name,
135,270✔
3710
                     vcode_var_flags_t flags)
3711
{
3712
   assert(active_unit != NULL);
135,270✔
3713

3714
   vcode_var_t var = active_unit->vars.count;
135,270✔
3715
   var_t *v = var_array_alloc(&(active_unit->vars));
135,270✔
3716
   memset(v, '\0', sizeof(var_t));
135,270✔
3717
   v->type  = type;
135,270✔
3718
   v->stamp = stamp;
135,270✔
3719
   v->name  = name;
135,270✔
3720
   v->flags = flags;
135,270✔
3721

3722
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
135,270✔
3723

3724
   return var;
135,270✔
3725
}
3726

3727
vcode_reg_t emit_param(vcode_type_t type, vcode_stamp_t stamp, ident_t name)
43,975✔
3728
{
3729
   assert(active_unit != NULL);
43,975✔
3730

3731
   param_t *p = param_array_alloc(&(active_unit->params));
43,975✔
3732
   memset(p, '\0', sizeof(param_t));
43,975✔
3733
   p->type  = type;
43,975✔
3734
   p->stamp = stamp;
43,975✔
3735
   p->name  = name;
43,975✔
3736
   p->reg   = vcode_add_reg(type, stamp);
43,975✔
3737

3738
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
43,975✔
3739

3740
   return p->reg;
43,975✔
3741
}
3742

3743
vcode_reg_t emit_load(vcode_var_t var)
85,828✔
3744
{
3745
   // Try scanning backwards through the block for another load or store to
3746
   // this variable
3747
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
85,828✔
3748
   vcode_reg_t fold = VCODE_INVALID_REG;
85,828✔
3749
   VCODE_FOR_EACH_OP(other) {
1,268,737✔
3750
      switch (state) {
1,203,025✔
3751
      case EAGER:
488,026✔
3752
         if (other->kind == VCODE_OP_LOAD && other->address == var)
488,026✔
3753
            return other->result;
5,342✔
3754
         else if (other->kind == VCODE_OP_STORE && other->address == var)
482,684✔
3755
            return other->args.items[0];
14,774✔
3756
         else if (other->kind == VCODE_OP_FCALL
467,910✔
3757
                  || other->kind == VCODE_OP_PCALL
467,910✔
3758
                  || other->kind == VCODE_OP_FILE_READ
3759
                  || other->kind == VCODE_OP_FILE_OPEN
3760
                  || other->kind == VCODE_OP_STORE_INDIRECT
3761
                  || other->kind == VCODE_OP_DEALLOCATE)
3762
            state = CONSERVATIVE;   // May write to variable
13,207✔
3763
         break;
3764

3765
      case CONSERVATIVE:
666,324✔
3766
         if (other->kind == VCODE_OP_LOAD && other->address == var
666,324✔
3767
             && fold == VCODE_INVALID_REG)
5,952✔
3768
            fold = other->result;
4,713✔
3769
         else if (other->kind == VCODE_OP_STORE && other->address == var
661,611✔
3770
                  && fold == VCODE_INVALID_REG)
3,533✔
3771
            fold = other->args.items[0];
3,293✔
3772
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
658,318✔
3773
            state = UNSAFE;
3774
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
656,007✔
3775
            state = UNSAFE;   // Nested call captures variables
184✔
3776
         break;
3777

3778
      case UNSAFE:
3779
         break;
3780
      }
3781
   }
3782

3783
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
65,712✔
3784
      return fold;
3785

3786
   var_t *v = vcode_var_data(var);
58,251✔
3787

3788
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
58,251✔
3789
   op->address = var;
58,251✔
3790
   op->result  = vcode_add_reg(v->type, v->stamp);
58,251✔
3791

3792
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
58,251✔
3793

3794
   return op->result;
3795
}
3796

3797
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
136,179✔
3798
{
3799
   VCODE_FOR_EACH_OP(other) {
1,639,824✔
3800
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,550,746✔
3801
          && other->args.items[0] == reg) {
228,039✔
3802
         return other->result;
15,580✔
3803
      }
3804
      else if (other->kind == VCODE_OP_FCALL
1,535,166✔
3805
               || other->kind == VCODE_OP_PCALL
1,535,166✔
3806
               || other->kind == VCODE_OP_STORE
3807
               || other->kind == VCODE_OP_STORE_INDIRECT
3808
               || other->kind == VCODE_OP_MEMSET
3809
               || other->kind == VCODE_OP_COPY
3810
               || other->kind == VCODE_OP_FILE_READ)
3811
         break;   // May write to this pointer
3812
   }
3813

3814
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
120,599✔
3815
   vcode_add_arg(op, reg);
120,599✔
3816

3817
   vcode_type_t rtype = vcode_reg_type(reg);
120,599✔
3818

3819
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
120,599✔
3820
                "load indirect with non-pointer argument");
3821

3822
   vcode_type_t deref = vtype_pointed(rtype);
120,599✔
3823
   op->result = vcode_add_reg(deref, vcode_reg_stamp(reg));
120,599✔
3824

3825
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
120,599✔
3826

3827
   return op->result;
3828
}
3829

3830
void emit_store(vcode_reg_t reg, vcode_var_t var)
136,410✔
3831
{
3832
   // Any previous store to this variable in this block is dead
3833
   VCODE_FOR_EACH_OP(other) {
2,791,140✔
3834
      if (other->kind == VCODE_OP_STORE && other->address == var) {
2,674,895✔
3835
         other->kind = VCODE_OP_COMMENT;
384✔
3836
         other->comment =
768✔
3837
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
384✔
3838
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
384✔
3839
      }
3840
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
2,674,511✔
3841
         break;   // Needs to get variable for display
3842
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
2,665,745✔
3843
               && other->address == var)
62,152✔
3844
         break;   // Previous value may be used
3845
   }
3846

3847
   var_t *v = vcode_var_data(var);
136,410✔
3848
   reg_t *r = vcode_reg_data(reg);
136,410✔
3849

3850
   op_t *op = vcode_add_op(VCODE_OP_STORE);
136,410✔
3851
   vcode_add_arg(op, reg);
136,410✔
3852
   op->address = var;
136,410✔
3853

3854
   VCODE_ASSERT(vtype_eq(v->type, r->type),
136,410✔
3855
                "variable and stored value do not have same type");
3856
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
136,410✔
3857
}
136,410✔
3858

3859
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
24,068✔
3860
{
3861
   reg_t *p = vcode_reg_data(ptr);
24,068✔
3862
   reg_t *r = vcode_reg_data(reg);
24,068✔
3863

3864
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
24,068✔
3865
   vcode_add_arg(op, reg);
24,068✔
3866
   vcode_add_arg(op, ptr);
24,068✔
3867

3868
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
24,068✔
3869
                "store indirect target is not a pointer");
3870
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
24,068✔
3871
                "pointer and stored value do not have same type");
3872
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
24,068✔
3873
}
24,068✔
3874

3875
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
93,569✔
3876
                              vcode_reg_t locus)
3877
{
3878
   // Reuse any previous operation in this block with the same arguments
3879
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
2,306,618✔
3880
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
119,594✔
3881
         return other->result;
8,538✔
3882
   }
3883

3884
   op_t *op = vcode_add_op(kind);
85,031✔
3885
   vcode_add_arg(op, lhs);
85,031✔
3886
   vcode_add_arg(op, rhs);
85,031✔
3887
   if (locus != VCODE_INVALID_REG)
85,031✔
3888
      vcode_add_arg(op, locus);
10,283✔
3889

3890
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
85,031✔
3891

3892
   vcode_type_t lhs_type = vcode_reg_type(lhs);
85,031✔
3893
   vcode_type_t rhs_type = vcode_reg_type(rhs);
85,031✔
3894

3895
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
85,031✔
3896
                "arguments to %s are not the same type", vcode_op_string(kind));
3897

3898
   return op->result;
85,031✔
3899
}
3900

3901
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
74,715✔
3902
                               vcode_reg_t locus)
3903
{
3904
   int64_t lconst, rconst;
74,715✔
3905
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
74,715✔
3906
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
74,715✔
3907
   if (l_is_const && r_is_const)
74,715✔
3908
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
36,991✔
3909
   else if (r_is_const && rconst == 1)
37,724✔
3910
      return lhs;
3911
   else if (l_is_const && lconst == 1)
7,576✔
3912
      return rhs;
3913
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
6,665✔
3914
      return emit_const(vcode_reg_type(lhs), 0);
95✔
3915

3916
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
6,570✔
3917

3918
   double rl_low, rl_high, rr_low, rr_high;
6,570✔
3919
   int64_t l_low, l_high, r_low, r_high;
6,570✔
3920

3921
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
6,570✔
3922
       && vcode_reg_bounds(rhs, &r_low, &r_high)) {
5,858✔
3923
      const int64_t ll = smul64(l_low, r_low);
5,858✔
3924
      const int64_t lh = smul64(l_low, r_high);
5,858✔
3925
      const int64_t hl = smul64(l_high, r_low);
5,858✔
3926
      const int64_t hh = smul64(l_high, r_high);
5,858✔
3927

3928
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
5,858✔
3929
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
5,858✔
3930

3931
      if (min > INT64_MIN && max < INT64_MAX) {
5,858✔
3932
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
3,303✔
3933
         if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
3,303✔
3934
            op = VCODE_OP_MUL;   // Cannot overflow
949✔
3935
            locus = VCODE_INVALID_REG;
949✔
3936
         }
3937
      }
3938

3939
      vstamp = vstamp_int(min, max);
5,858✔
3940
   }
3941
   else if (vcode_reg_bounds_real(lhs, &rl_low, &rl_high)
712✔
3942
            && vcode_reg_bounds_real(rhs, &rr_low, &rr_high)) {
712✔
3943
      const double ll = rl_low * rr_low;
712✔
3944
      const double lh = rl_low * rr_high;
712✔
3945
      const double hl = rl_high * rr_low;
712✔
3946
      const double hh = rl_high * rr_high;
712✔
3947

3948
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,656✔
3949
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,776✔
3950

3951
      vstamp = vstamp_real(min, max);
712✔
3952
   }
3953

3954
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
6,570✔
3955

3956
   if (vstamp != VCODE_INVALID_TYPE)
6,570✔
3957
      vcode_reg_data(reg)->stamp = vstamp;
6,570✔
3958

3959
   return reg;
3960
}
3961

3962
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
70,188✔
3963
{
3964
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
70,188✔
3965
}
3966

3967
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
4,527✔
3968
{
3969
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
4,527✔
3970

3971
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
4,527✔
3972
                "trapping add may only be used with integer types");
3973

3974
   return result;
4,527✔
3975
}
3976

3977
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
2,696✔
3978
{
3979
   int64_t lconst, rconst;
2,696✔
3980
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
2,696✔
3981
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
2,696✔
3982
   if (l_is_const && r_is_const && rconst != 0)
2,696✔
3983
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
44✔
3984
   else if (r_is_const && rconst == 1)
2,652✔
3985
      return lhs;
3986

3987
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
2,648✔
3988

3989
   int64_t l_low, l_high;
2,648✔
3990
   if (vcode_reg_bounds(lhs, &l_low, &l_high)) {
2,648✔
3991
      if (r_is_const && rconst != 0) {
2,228✔
3992
         reg_t *rr = vcode_reg_data(reg);
2,127✔
3993
         rr->stamp = vstamp_int(l_low / rconst, l_high / rconst);
2,127✔
3994
      }
3995
   }
3996
   else {
3997
      reg_t *rr = vcode_reg_data(reg);
420✔
3998
      rr->stamp = vstamp_real(-INFINITY, INFINITY);
420✔
3999
   }
4000

4001
   return reg;
4002
}
4003

4004
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
191✔
4005
{
4006
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
191✔
4007
}
4008

4009
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
233✔
4010
{
4011
   int64_t rconst;
233✔
4012
   if (vcode_reg_const(rhs, &rconst)) {
233✔
4013
      if (rconst == 0)
113✔
4014
         return emit_const(vcode_reg_type(lhs), 1);
51✔
4015
      else if (rconst == 1)
62✔
4016
         return lhs;
4017
   }
4018

4019
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
181✔
4020

4021
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
181✔
4022
                "trapping exp may only be used with integer types");
4023

4024
   return result;
4025
}
4026

4027
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
268✔
4028
{
4029
   int64_t lconst, rconst;
268✔
4030
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
268✔
4031
       && lconst > 0 && rconst > 0)
19✔
4032
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
4✔
4033

4034
   int64_t l_low, l_high, r_low, r_high;
264✔
4035
   if (vcode_reg_bounds(lhs, &l_low, &l_high) && l_low >= 0
264✔
4036
       && vcode_reg_bounds(rhs, &r_low, &r_high) && r_low >= 0) {
125✔
4037
      // If both arguments are non-negative then rem is equivalent and
4038
      // cheaper to compute
4039
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
120✔
4040

4041
      reg_t *rr = vcode_reg_data(reg);
120✔
4042
      rr->stamp = vstamp_int(0, MAX(0, r_high - 1));
120✔
4043

4044
      return reg;
120✔
4045
   }
4046
   else
4047
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
144✔
4048
}
4049

4050
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
1,562✔
4051
{
4052
   int64_t lconst, rconst;
1,562✔
4053
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
1,562✔
4054
       && lconst > 0 && rconst > 0)
2✔
4055
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
4056

4057
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
1,562✔
4058

4059
   int64_t l_low, l_high, r_low, r_high;
1,562✔
4060
   if (vcode_reg_bounds(lhs, &l_low, &l_high) && l_low >= 0
1,562✔
4061
       && vcode_reg_bounds(rhs, &r_low, &r_high) && r_low >= 0) {
1,045✔
4062
      reg_t *rr = vcode_reg_data(reg);
1,040✔
4063
      rr->stamp = vstamp_int(0, r_high - 1);
1,040✔
4064
   }
4065

4066
   return reg;
4067
}
4068

4069
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
69,008✔
4070
                               vcode_reg_t locus)
4071
{
4072
   int64_t lconst, rconst;
69,008✔
4073
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
69,008✔
4074
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
69,008✔
4075
   if (l_is_const && r_is_const)
69,008✔
4076
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
17,188✔
4077
   else if (r_is_const && rconst == 0)
51,820✔
4078
      return lhs;
4079
   else if (l_is_const && lconst == 0)
51,637✔
4080
      return rhs;
4081

4082
   int64_t l_low, l_high, r_low, r_high;
29,215✔
4083
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
29,215✔
4084
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
29,215✔
4085
       && vcode_reg_bounds(rhs, &r_low, &r_high))  {
28,793✔
4086

4087
      int64_t rbl = sadd64(l_low, r_low);
28,793✔
4088
      int64_t rbh = sadd64(l_high, r_high);
28,793✔
4089

4090
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
28,793✔
4091
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
15,305✔
4092
         if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
15,305✔
4093
            op = VCODE_OP_ADD;   // Cannot overflow
2,048✔
4094
            locus = VCODE_INVALID_REG;
2,048✔
4095
         }
4096
      }
4097

4098
      vstamp = vstamp_int(rbl, rbh);
28,793✔
4099
   }
4100

4101
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
29,215✔
4102

4103
   if (vstamp != VCODE_INVALID_STAMP)
29,215✔
4104
      vcode_reg_data(reg)->stamp = vstamp;
28,793✔
4105

4106
   return reg;
4107
}
4108

4109
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
59,802✔
4110
{
4111
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
59,802✔
4112
}
4113

4114
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
9,206✔
4115
{
4116
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
9,206✔
4117

4118
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
9,206✔
4119
                "trapping add may only be used with integer types");
4120

4121
   return result;
9,206✔
4122
}
4123

4124
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
64,409✔
4125
                               vcode_reg_t locus)
4126
{
4127
   int64_t lconst, rconst;
64,409✔
4128
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
64,409✔
4129
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
64,409✔
4130
   if (l_is_const && r_is_const)
64,409✔
4131
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
11,802✔
4132
   else if (r_is_const && rconst == 0)
52,607✔
4133
      return lhs;
4134
   else if (l_is_const && lconst == 0)
45,613✔
4135
      return emit_neg(rhs);
1,163✔
4136

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

4142
      int64_t rbl = ssub64(l_low, r_high);
44,070✔
4143
      int64_t rbh = ssub64(l_high, r_low);
44,070✔
4144

4145
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
44,070✔
4146
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
41,319✔
4147
         if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
41,319✔
4148
            op = VCODE_OP_SUB;   // Cannot overflow
6,894✔
4149
            locus = VCODE_INVALID_REG;
6,894✔
4150
         }
4151
      }
4152

4153
      vstamp = vstamp_int(rbl, rbh);
44,070✔
4154
   }
4155

4156
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
44,450✔
4157

4158
   if (vstamp != VCODE_INVALID_TYPE)
44,450✔
4159
      vcode_reg_data(reg)->stamp = vstamp;
44,070✔
4160

4161
   return reg;
4162
}
4163

4164
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
54,841✔
4165
{
4166
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
54,841✔
4167
}
4168

4169
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
9,568✔
4170
{
4171
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
9,568✔
4172

4173
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
9,568✔
4174
                "trapping sub may only be used with integer types");
4175

4176
   return result;
9,568✔
4177
}
4178

4179
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
112,630✔
4180
{
4181
   switch (vtype_kind(var->type)) {
112,630✔
4182
   case VCODE_TYPE_CARRAY:
40,121✔
4183
      op->type = vtype_pointer(vtype_elem(var->type));
40,121✔
4184
      op->result = vcode_add_reg(op->type, var->stamp);
40,121✔
4185
      break;
40,121✔
4186

4187
   case VCODE_TYPE_RECORD:
8,783✔
4188
      op->type = vtype_pointer(var->type);
8,783✔
4189
      op->result = vcode_add_reg(op->type, VCODE_INVALID_STAMP);
8,783✔
4190
      break;
8,783✔
4191

4192
   case VCODE_TYPE_INT:
63,726✔
4193
   case VCODE_TYPE_FILE:
4194
   case VCODE_TYPE_ACCESS:
4195
   case VCODE_TYPE_REAL:
4196
   case VCODE_TYPE_UARRAY:
4197
   case VCODE_TYPE_POINTER:
4198
   case VCODE_TYPE_SIGNAL:
4199
   case VCODE_TYPE_CONTEXT:
4200
   case VCODE_TYPE_OFFSET:
4201
   case VCODE_TYPE_TRIGGER:
4202
   case VCODE_TYPE_RESOLUTION:
4203
      op->type = vtype_pointer(var->type);
63,726✔
4204
      op->result = vcode_add_reg(op->type, var->stamp);
63,726✔
4205
      break;
63,726✔
4206

4207
   default:
4208
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4209
                   istr(var->name));
4210
   }
4211
}
112,630✔
4212

4213
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
60,501✔
4214
{
4215
   // Try to find a previous index of this var by this offset
4216
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
2,798,757✔
4217
      if (other->address == var
160,892✔
4218
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
10,707✔
4219
              || (offset != VCODE_INVALID_REG
×
4220
                  && other->args.items[0] == offset)))
×
4221
         return other->result;
10,707✔
4222
   }
4223

4224
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
49,794✔
4225
   op->address = var;
49,794✔
4226

4227
   if (offset != VCODE_INVALID_REG)
49,794✔
4228
      vcode_add_arg(op, offset);
×
4229

4230
   vcode_calculate_var_index_type(op, vcode_var_data(var));
49,794✔
4231

4232
   if (offset != VCODE_INVALID_REG)
49,794✔
4233
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4234
                   "index offset r%d does not have offset type", offset);
4235

4236
   return op->result;
49,794✔
4237
}
4238

4239
vcode_reg_t emit_cast(vcode_type_t type, vcode_stamp_t stamp, vcode_reg_t reg)
369,550✔
4240
{
4241
   if (vtype_eq(vcode_reg_type(reg), type))
369,550✔
4242
      return reg;
369,550✔
4243

4244
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
115,483✔
4245
   vtype_kind_t to   = vtype_kind(type);
115,483✔
4246

4247
   const bool integral =
230,966✔
4248
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
115,483✔
4249
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
115,483✔
4250

4251
   int64_t value;
115,483✔
4252
   if (integral && vcode_reg_const(reg, &value))
115,483✔
4253
      return emit_const(type, value);
18,292✔
4254

4255
   // Try to find a previous cast of this register to this type
4256
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,947,370✔
4257
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
201,695✔
4258
         return other->result;
22,010✔
4259
   }
4260

4261
   op_t *op = vcode_add_op(VCODE_OP_CAST);
75,181✔
4262
   vcode_add_arg(op, reg);
75,181✔
4263
   op->type  = type;
75,181✔
4264

4265
   static const vcode_type_t allowed[][2] = {
75,181✔
4266
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4267
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4268
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4269
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4270
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4271
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4272
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4273
   };
4274

4275
   if (integral) {
75,181✔
4276
      vtype_t *vt = vcode_type_data(type);
74,000✔
4277
      int64_t low = vt->low, high = vt->high;
74,000✔
4278

4279
      vstamp_t *rt = vcode_stamp_data(vcode_reg_data(reg)->stamp);
74,000✔
4280
      if (rt != NULL) {
74,000✔
4281
         VCODE_ASSERT(rt->kind == VCODE_STAMP_INT, "must be integer stamp");
18,297✔
4282
         low = MAX(low, rt->u.intg.low);
18,297✔
4283
         high = MIN(high, rt->u.intg.high);
18,297✔
4284
      }
4285

4286
      vstamp_t *bt = vcode_stamp_data(stamp);
74,000✔
4287
      if (bt != NULL) {
74,000✔
4288
         VCODE_ASSERT(bt->kind == VCODE_STAMP_INT, "must be integer stamp");
31,082✔
4289
         low = MAX(low, bt->u.intg.low);
31,082✔
4290
         high = MIN(high, bt->u.intg.high);
31,082✔
4291
      }
4292

4293
      stamp = vstamp_int(low, high);
74,000✔
4294
   }
4295

4296
   op->result = vcode_add_reg(type, stamp);
75,181✔
4297

4298
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
133,400✔
4299
      if (from == allowed[i][0] && to == allowed[i][1])
133,400✔
4300
         return op->result;
4301
   }
4302

4303
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4304
}
4305

4306
void emit_return(vcode_reg_t reg)
84,254✔
4307
{
4308
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
84,254✔
4309
   if (reg != VCODE_INVALID_REG) {
84,254✔
4310
      vcode_add_arg(op, reg);
31,726✔
4311

4312
      const vtype_kind_t rkind = vcode_reg_kind(reg);
31,726✔
4313
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY)
31,726✔
4314
         vcode_heap_allocate(reg);
5,872✔
4315

4316
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
31,726✔
4317
                   || active_unit->kind == VCODE_UNIT_THUNK
4318
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4319
                   "returning value fron non-function unit");
4320
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
31,726✔
4321
                    && rkind == VCODE_TYPE_INT)
4322
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4323
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4324
                       && rkind == VCODE_TYPE_ACCESS),
4325
                   "return value incorrect type");
4326
   }
4327
}
84,254✔
4328

4329
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
12,493✔
4330
                         vcode_reg_t values, vcode_reg_t reject,
4331
                         vcode_reg_t after)
4332
{
4333
   int64_t nconst;
12,493✔
4334
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
12,493✔
4335
      emit_comment("Skip empty waveform");
20✔
4336
      return;
20✔
4337
   }
4338

4339
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
12,473✔
4340
   vcode_add_arg(op, nets);
12,473✔
4341
   vcode_add_arg(op, nnets);
12,473✔
4342
   vcode_add_arg(op, values);
12,473✔
4343
   vcode_add_arg(op, reject);
12,473✔
4344
   vcode_add_arg(op, after);
12,473✔
4345

4346
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
12,473✔
4347
                "sched_waveform target is not signal");
4348
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
12,473✔
4349
                "sched_waveform net count is not offset type");
4350
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
12,473✔
4351
                "signal cannot be values argument for sched_waveform");
4352
}
4353

4354
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
93✔
4355
{
4356
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
93✔
4357
   vcode_add_arg(op, nets);
93✔
4358
   vcode_add_arg(op, nnets);
93✔
4359
   vcode_add_arg(op, values);
93✔
4360

4361
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
93✔
4362
                "force target is not signal");
4363
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
93✔
4364
                "force net count is not offset type");
4365
}
93✔
4366

4367
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
56✔
4368
{
4369
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
56✔
4370
   vcode_add_arg(op, nets);
56✔
4371
   vcode_add_arg(op, nnets);
56✔
4372

4373
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
56✔
4374
                "release target is not signal");
4375
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
56✔
4376
                "release net count is not offset type");
4377
}
56✔
4378

4379
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
32✔
4380
                     vcode_reg_t after)
4381
{
4382
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
32✔
4383
   vcode_add_arg(op, nets);
32✔
4384
   vcode_add_arg(op, nnets);
32✔
4385
   vcode_add_arg(op, reject);
32✔
4386
   vcode_add_arg(op, after);
32✔
4387

4388
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
32✔
4389
                "disconnect target is not signal");
4390
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
32✔
4391
                "disconnect net count is not offset type");
4392
}
32✔
4393

4394
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
45,883✔
4395
{
4396
   int64_t tconst;
45,883✔
4397
   if (vcode_reg_const(test, &tconst)) {
45,883✔
4398
      emit_jump(!!tconst ? btrue : bfalse);
5,421✔
4399
      return;
2,763✔
4400
   }
4401

4402
   op_t *op = vcode_add_op(VCODE_OP_COND);
43,120✔
4403
   vcode_add_arg(op, test);
43,120✔
4404
   vcode_add_target(op, btrue);
43,120✔
4405
   vcode_add_target(op, bfalse);
43,120✔
4406

4407
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
43,120✔
4408
                "cond test is not a bool");
4409
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
43,120✔
4410
                "invalid cond targets");
4411
}
4412

4413
vcode_reg_t emit_neg(vcode_reg_t lhs)
8,762✔
4414
{
4415
   int64_t lconst;
8,762✔
4416
   if (vcode_reg_const(lhs, &lconst))
8,762✔
4417
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4418

4419
   op_t *op = vcode_add_op(VCODE_OP_NEG);
8,762✔
4420
   vcode_add_arg(op, lhs);
8,762✔
4421
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
8,762✔
4422

4423
   return op->result;
8,762✔
4424
}
4425

4426
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
594✔
4427
{
4428
   int64_t lconst;
594✔
4429
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
594✔
4430
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4431

4432
   reg_t *lhs_r = vcode_reg_data(lhs);
594✔
4433

4434
   vstamp_t *s = vcode_stamp_data(lhs_r->stamp);
594✔
4435
   if (s != NULL && s->kind == VCODE_STAMP_INT && s->u.intg.low >= 0)
594✔
4436
      return emit_neg(lhs);   // Cannot overflow
257✔
4437

4438
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
337✔
4439
   vcode_add_arg(op, lhs);
337✔
4440
   vcode_add_arg(op, locus);
337✔
4441

4442
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
337✔
4443
                "locus argument to trap neg must be a debug locus");
4444
   VCODE_ASSERT(vtype_kind(lhs_r->type) == VCODE_TYPE_INT,
337✔
4445
                "trapping neg may only be used with integer types");
4446

4447
   return (op->result = vcode_add_reg(lhs_r->type, VCODE_INVALID_STAMP));
337✔
4448
}
4449

4450
vcode_reg_t emit_abs(vcode_reg_t lhs)
906✔
4451
{
4452
   int64_t lconst;
906✔
4453
   if (vcode_reg_const(lhs, &lconst))
906✔
4454
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4455

4456
   op_t *op = vcode_add_op(VCODE_OP_ABS);
905✔
4457
   vcode_add_arg(op, lhs);
905✔
4458
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
905✔
4459

4460
   return op->result;
905✔
4461
}
4462

4463
void emit_comment(const char *fmt, ...)
137,554✔
4464
{
4465
#ifndef NDEBUG
4466
   va_list ap;
137,554✔
4467
   va_start(ap, fmt);
137,554✔
4468

4469
   char *buf = xvasprintf(fmt, ap);
137,554✔
4470
   for (char *p = buf + strlen(buf) - 1;
137,554✔
4471
        p >= buf && isspace_iso88591(*p); p--)
137,554✔
4472
      *p = '\0';
×
4473

4474
   vcode_add_op(VCODE_OP_COMMENT)->comment = buf;
137,554✔
4475
   va_end(ap);
137,554✔
4476
#endif
4477
}
137,554✔
4478

4479
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
26,078✔
4480
                        vcode_reg_t rfalse)
4481
{
4482
   int64_t tconst;
26,078✔
4483
   if (vcode_reg_const(test, &tconst))
26,078✔
4484
      return !!tconst ? rtrue : rfalse;
6,730✔
4485
   else if (rtrue == rfalse)
19,348✔
4486
      return rtrue;
4487

4488
   // Find a previous identical select
4489
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
426,033✔
4490
      if (other->args.items[0] == test && other->args.items[1] == rtrue
16,260✔
4491
          && other->args.items[2] == rfalse)
845✔
4492
         return other->result;
712✔
4493
   }
4494

4495
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
18,401✔
4496
   vcode_add_arg(op, test);
18,401✔
4497
   vcode_add_arg(op, rtrue);
18,401✔
4498
   vcode_add_arg(op, rfalse);
18,401✔
4499
   op->result = vcode_add_reg(vcode_reg_type(rtrue), VCODE_INVALID_STAMP);
18,401✔
4500

4501
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
18,401✔
4502
                "select test must have bool type");
4503
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
18,401✔
4504
                "select arguments are not the same type");
4505

4506
   return op->result;
18,401✔
4507
}
4508

4509
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
601✔
4510
{
4511
   switch (op) {
601✔
4512
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
60✔
4513
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
477✔
4514
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
16✔
4515
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
16✔
4516
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
16✔
4517
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
16✔
4518
   default:
×
4519
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
4520
   }
4521
}
4522

4523
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
9,133✔
4524
{
4525
   vcode_type_t vtbool = vtype_bool();
9,133✔
4526

4527
   int64_t lconst, rconst;
9,133✔
4528
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
9,133✔
4529
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
9,133✔
4530
   if (l_is_const && r_is_const) {
9,133✔
4531
      switch (op) {
8✔
4532
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
4533
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
4534
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
×
4535
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
8✔
4536
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
4537
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
4538
      default:
×
4539
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4540
      }
4541
   }
4542
   else if (l_is_const)
9,125✔
4543
      return emit_logical_identity(op, rhs, !!lconst);
468✔
4544
   else if (r_is_const)
8,657✔
4545
      return emit_logical_identity(op, lhs, !!rconst);
133✔
4546
   else if (lhs == rhs) {
8,524✔
4547
      switch (op) {
36✔
4548
      case VCODE_OP_AND:
4549
      case VCODE_OP_OR:
4550
         return lhs;
4551
      case VCODE_OP_NAND:
8✔
4552
      case VCODE_OP_NOR:
4553
         return emit_not(lhs);
8✔
4554
      case VCODE_OP_XOR:
4✔
4555
         return emit_const(vtbool, 0);
4✔
4556
      case VCODE_OP_XNOR:
×
4557
         return emit_const(vtbool, 1);
×
4558
      default:
×
4559
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4560
      }
4561
   }
4562

4563
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
8,488✔
4564

4565
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
8,488✔
4566
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4567
                "arguments to %s are not boolean", vcode_op_string(op));
4568

4569
   return result;
4570
}
4571

4572
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
3,018✔
4573
{
4574
   return emit_logical(VCODE_OP_OR, lhs, rhs);
3,018✔
4575
}
4576

4577
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
5,811✔
4578
{
4579
   return emit_logical(VCODE_OP_AND, lhs, rhs);
5,811✔
4580
}
4581

4582
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
65✔
4583
{
4584
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
65✔
4585
}
4586

4587
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
66✔
4588
{
4589
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
66✔
4590
}
4591

4592
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
100✔
4593
{
4594
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
100✔
4595
}
4596

4597
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
73✔
4598
{
4599
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
73✔
4600
}
4601

4602
vcode_reg_t emit_not(vcode_reg_t arg)
3,480✔
4603
{
4604
   int64_t cval;
3,480✔
4605
   if (vcode_reg_const(arg, &cval))
3,480✔
4606
      return emit_const(vtype_bool(), !cval);
36✔
4607

4608
   op_t *op = vcode_add_op(VCODE_OP_NOT);
3,444✔
4609
   vcode_add_arg(op, arg);
3,444✔
4610

4611
   vcode_type_t vtbool = vtype_bool();
3,444✔
4612
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
3,444✔
4613
                "argument to not is not boolean");
4614

4615
   return (op->result = vcode_add_reg(vtbool, VCODE_INVALID_STAMP));
3,444✔
4616
}
4617

4618
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
63,828✔
4619
{
4620
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
2,445,716✔
4621
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
208,770✔
4622
         bool match = true;
4623
         for (int i = 0; match && i < ndims; i++) {
26,277✔
4624
            match = other->args.items[i*3 + 1] == dims[i].left
13,204✔
4625
               && other->args.items[i*3 + 2] == dims[i].right
11,999✔
4626
               && other->args.items[i*3 + 3] == dims[i].dir;
24,813✔
4627
         }
4628
         if (match)
13,073✔
4629
            return other->result;
11,478✔
4630
      }
4631
   }
4632

4633
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
52,350✔
4634
   vcode_add_arg(op, data);
52,350✔
4635
   for (int i = 0; i < ndims; i++) {
106,526✔
4636
      vcode_add_arg(op, dims[i].left);
54,176✔
4637
      vcode_add_arg(op, dims[i].right);
54,176✔
4638
      vcode_add_arg(op, dims[i].dir);
54,176✔
4639
   }
4640

4641
   vcode_type_t ptr_type = vcode_reg_type(data);
52,350✔
4642
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
52,350✔
4643
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
52,350✔
4644
                "wrapped data is not pointer or signal");
4645

4646
#ifdef DEBUG
4647
   for (int i = 0; i < ndims; i++) {
106,526✔
4648
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
54,176✔
4649
                   "dimension %d left bound must be scalar", i + 1);
4650
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
54,176✔
4651
                   "dimension %d right bound must be scalar", i + 1);
4652
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
54,176✔
4653
                   "dimension %d direction must be bool", i + 1);
4654
   }
4655
#endif
4656

4657
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
104,700✔
4658
      ? vtype_pointed(ptr_type) : ptr_type;
52,350✔
4659

4660
   op->result = vcode_add_reg(vtype_uarray(ndims, elem), vcode_reg_stamp(data));
52,350✔
4661

4662
   return op->result;
52,350✔
4663
}
4664

4665
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
142,906✔
4666
                                  vcode_reg_t array, unsigned dim,
4667
                                  unsigned arg_index)
4668
{
4669
   // Reuse any previous operation in this block with the same arguments
4670
   VCODE_FOR_EACH_OP(other) {
1,665,117✔
4671
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,601,483✔
4672
          && (rtype == VCODE_INVALID_TYPE
33,341✔
4673
              || vtype_eq(rtype, vcode_reg_type(other->result))))
14,431✔
4674
         return other->result;
33,341✔
4675
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,568,142✔
4676
         return other->args.items[1 + (dim * 3) + arg_index];
45,931✔
4677
   }
4678

4679
   op_t *op = vcode_add_op(o);
63,634✔
4680
   vcode_add_arg(op, array);
63,634✔
4681
   op->dim = dim;
63,634✔
4682

4683
   vcode_type_t atype = vcode_reg_type(array);
63,634✔
4684
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
63,634✔
4685
                "cannot use %s with non-uarray type", vcode_op_string(o));
4686

4687
   vtype_t *vt = vcode_type_data(atype);
63,634✔
4688
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
63,634✔
4689

4690
   if (rtype == VCODE_INVALID_TYPE)
63,634✔
4691
      rtype = vtype_offset();
41,113✔
4692

4693
   return (op->result = vcode_add_reg(rtype, VCODE_INVALID_STAMP));
63,634✔
4694
}
4695

4696
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
52,739✔
4697
{
4698
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
52,739✔
4699
                         array, dim, 0);
4700
}
4701

4702
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
37,766✔
4703
{
4704
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
37,766✔
4705
                         array, dim, 1);
4706
}
4707

4708
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
52,401✔
4709
{
4710
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
52,401✔
4711
                         array, dim, 2);
4712
}
4713

4714
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
63,357✔
4715
{
4716
   VCODE_FOR_EACH_OP(other) {
1,053,204✔
4717
      if (other->kind == VCODE_OP_UARRAY_LEN) {
1,022,874✔
4718
         if (other->args.items[0] == array && other->dim == dim)
65,024✔
4719
            return other->result;
12,990✔
4720
      }
4721
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
957,850✔
4722
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
20,037✔
4723
                      "array dimension %d out of bounds", dim);
4724

4725
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
20,037✔
4726
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
20,037✔
4727
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
20,037✔
4728
         return emit_range_length(left_reg, right_reg, dir_reg);
20,037✔
4729
      }
4730
   }
4731

4732
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
30,330✔
4733
   vcode_add_arg(op, array);
30,330✔
4734
   op->dim = dim;
30,330✔
4735

4736
   vcode_type_t atype = vcode_reg_type(array);
30,330✔
4737
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
30,330✔
4738
                "cannot use uarray len with non-uarray type");
4739

4740
   vtype_t *vt = vcode_type_data(atype);
30,330✔
4741
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
30,330✔
4742

4743
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
30,330✔
4744

4745
   return op->result;
30,330✔
4746
}
4747

4748
vcode_reg_t emit_unwrap(vcode_reg_t array)
49,257✔
4749
{
4750
   VCODE_FOR_EACH_OP(other) {
2,458,284✔
4751
      if (other->kind == VCODE_OP_WRAP && other->result == array)
2,422,657✔
4752
         return other->args.items[0];
11,302✔
4753
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
2,411,355✔
4754
         return other->result;
2,328✔
4755
   }
4756

4757
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
35,627✔
4758
   vcode_add_arg(op, array);
35,627✔
4759

4760
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
35,627✔
4761
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
35,627✔
4762
                "unwrap can only only be used with uarray types");
4763

4764
   vcode_type_t elem = vt->elem;
35,627✔
4765

4766
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
35,627✔
4767
      ? elem : vtype_pointer(elem);
35,627✔
4768

4769
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
35,627✔
4770
}
4771

4772
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
55,751✔
4773
                            vcode_reg_t dir)
4774
{
4775
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
3,041,646✔
4776
      if (other->args.items[0] == left
×
4777
          && other->args.items[1] == right
×
4778
          && other->args.items[2] == dir)
×
4779
         return other->result;
×
4780
   }
4781

4782
   int64_t dir_const, l_low, l_high, r_low, r_high;
55,751✔
4783
   if (vcode_reg_const(dir, &dir_const)
55,751✔
4784
       && vcode_reg_bounds(left, &l_low, &l_high)
51,567✔
4785
       && vcode_reg_bounds(right, &r_low, &r_high)) {
51,567✔
4786

4787
      if (dir_const == RANGE_TO && l_low > r_high)
51,567✔
4788
         return emit_const(vtype_bool(), 1);
88✔
4789
      else if (dir_const == RANGE_TO && l_high <= r_low)
51,479✔
4790
         return emit_const(vtype_bool(), 0);
40,166✔
4791
      else if (dir_const == RANGE_DOWNTO && r_low > l_high)
11,313✔
4792
         return emit_const(vtype_bool(), 1);
1,106✔
4793
      else if (dir_const == RANGE_DOWNTO && r_high <= l_low)
10,207✔
4794
         return emit_const(vtype_bool(), 0);
2,679✔
4795
      else if (dir_const == RANGE_TO)
7,528✔
4796
         return emit_cmp(VCODE_CMP_GT, left, right);
4,095✔
4797
      else
4798
         return emit_cmp(VCODE_CMP_GT, right, left);
3,433✔
4799
   }
4800

4801
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
4,184✔
4802
   vcode_add_arg(op, left);
4,184✔
4803
   vcode_add_arg(op, right);
4,184✔
4804
   vcode_add_arg(op, dir);
4,184✔
4805

4806
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
4,184✔
4807
                "range left and right have different types");
4808
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
4,184✔
4809
                "dir argument to range length is not int");
4810

4811
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
4,184✔
4812
}
4813

4814
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
20,097✔
4815
                              vcode_reg_t dir)
4816
{
4817
   vcode_reg_t left_array = VCODE_INVALID_REG,
20,097✔
4818
      right_array = VCODE_INVALID_REG,
20,097✔
4819
      dir_array = VCODE_INVALID_REG;
20,097✔
4820
   int left_dim = -1, right_dim = -1, dir_dim = -1;
20,097✔
4821

4822
   VCODE_FOR_EACH_OP(other) {
402,633✔
4823
      if (other->kind == VCODE_OP_RANGE_LENGTH
389,722✔
4824
          && other->args.items[0] == left
9,801✔
4825
          && other->args.items[1] == right
7,643✔
4826
          && other->args.items[2] == dir)
7,186✔
4827
         return other->result;
7,186✔
4828
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
382,536✔
4829
         left_array = other->args.items[0];
567✔
4830
         left_dim = other->dim;
567✔
4831
      }
4832
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
381,969✔
4833
         right_array = other->args.items[0];
567✔
4834
         right_dim = other->dim;
567✔
4835
      }
4836
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
381,402✔
4837
         dir_array = other->args.items[0];
1,040✔
4838
         dir_dim = other->dim;
1,040✔
4839
      }
4840
   }
4841

4842
   if (left_array != VCODE_INVALID_REG && left_array == right_array
12,911✔
4843
       && right_array == dir_array && left_dim == right_dim
567✔
4844
       && right_dim == dir_dim)
567✔
4845
      return emit_uarray_len(left_array, left_dim);
567✔
4846

4847
   int64_t lconst, rconst, dconst;
12,344✔
4848
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
12,344✔
4849
       && vcode_reg_const(right, &rconst)) {
6,898✔
4850

4851
      int64_t diff;
2,797✔
4852
      if (dconst == RANGE_TO)
2,797✔
4853
         diff = rconst - lconst;
2,344✔
4854
      else
4855
         diff = lconst - rconst;
453✔
4856

4857
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
2,797✔
4858
   }
4859

4860
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
9,547✔
4861
   vcode_add_arg(op, left);
9,547✔
4862
   vcode_add_arg(op, right);
9,547✔
4863
   vcode_add_arg(op, dir);
9,547✔
4864

4865
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
9,547✔
4866
                "range left and right have different types");
4867
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
9,547✔
4868
                "dir argument to range length is not int");
4869

4870
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
9,547✔
4871

4872
   return op->result;
9,547✔
4873
}
4874

4875
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
80,252✔
4876
{
4877
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
732,030✔
4878
      if (other->hops == hops && other->address == var)
102,490✔
4879
         return other->result;
17,416✔
4880
   }
4881

4882
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
62,836✔
4883
   op->hops    = hops;
62,836✔
4884
   op->address = var;
62,836✔
4885

4886
   VCODE_ASSERT(hops > 0, "invalid hop count");
62,836✔
4887

4888
   vcode_unit_t vu = active_unit;
62,836✔
4889
   for (int i = 0; i < hops; i++) {
139,293✔
4890
      vu = vu->context;
76,457✔
4891
      VCODE_ASSERT(vu, "hop count is greater than depth");
76,457✔
4892
   }
4893

4894
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
62,836✔
4895

4896
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
62,836✔
4897

4898
   return op->result;
62,836✔
4899
}
4900

4901
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
28,535✔
4902
                             vcode_reg_t size, vcode_reg_t value,
4903
                             vcode_reg_t flags, vcode_reg_t locus,
4904
                             vcode_reg_t offset)
4905
{
4906
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
28,535✔
4907
   vcode_add_arg(op, count);
28,535✔
4908
   vcode_add_arg(op, size);
28,535✔
4909
   vcode_add_arg(op, value);
28,535✔
4910
   vcode_add_arg(op, flags);
28,535✔
4911
   vcode_add_arg(op, locus);
28,535✔
4912
   if (offset != VCODE_INVALID_REG)
28,535✔
4913
      vcode_add_arg(op, offset);
10,189✔
4914

4915
   vcode_type_t vtype = vcode_reg_type(value);
28,535✔
4916
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
28,535✔
4917
   VCODE_ASSERT(vtype_eq(vtype, type)
28,535✔
4918
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4919
                "init signal value type does not match signal type");
4920
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
28,535✔
4921
                "locus argument to init signal must be a debug locus");
4922
   VCODE_ASSERT(offset == VCODE_INVALID_REG
28,535✔
4923
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4924
                "init signal offset argument must have pointer type");
4925

4926
   vcode_type_t stype = vtype_signal(type);
28,535✔
4927
   return (op->result = vcode_add_reg(stype, VCODE_INVALID_STAMP));
28,535✔
4928
}
4929

4930
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
6,587✔
4931
{
4932
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
6,587✔
4933
   vcode_add_arg(op, signal);
6,587✔
4934
   vcode_add_arg(op, resolution);
6,587✔
4935

4936
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
6,587✔
4937
                "signal argument has wrong type");
4938

4939
   vcode_type_t rtype = vcode_reg_type(resolution);
6,587✔
4940
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
6,587✔
4941
                "resolution wrapper argument must be pointer");
4942
   VCODE_ASSERT(vtype_kind(vtype_pointed(rtype)) == VCODE_TYPE_RESOLUTION,
6,587✔
4943
                "resolution wrapper argument has wrong type");
4944
}
6,587✔
4945

4946
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
9,281✔
4947
{
4948
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
9,281✔
4949
   vcode_add_arg(op, src);
9,281✔
4950
   vcode_add_arg(op, dst);
9,281✔
4951
   vcode_add_arg(op, count);
9,281✔
4952

4953
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
9,281✔
4954
                "src argument to map signal is not a signal");
4955
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
9,281✔
4956
                "dst argument to map signal is not a signal");
4957
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
9,281✔
4958
                "count argument type to map signal is not offset");
4959
}
9,281✔
4960

4961
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
319✔
4962
{
4963
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
319✔
4964
   vcode_add_arg(op, src);
319✔
4965
   vcode_add_arg(op, dst);
319✔
4966
   vcode_add_arg(op, count);
319✔
4967

4968
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
319✔
4969
                "dst argument to map const is not a signal");
4970
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
319✔
4971
                "count argument type to map const is not offset");
4972
}
319✔
4973

4974
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
10,434✔
4975
{
4976
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
128,501✔
4977
      if (other->args.items[0] == target && other->args.items[1] == count)
17,071✔
4978
         return;
4979
   }
4980

4981
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
10,430✔
4982
   vcode_add_arg(op, target);
10,430✔
4983
   vcode_add_arg(op, count);
10,430✔
4984

4985
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
10,430✔
4986
                "target argument to drive signal is not a signal");
4987
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
10,430✔
4988
                "count argument type to drive signal is not offset");
4989
}
4990

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

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

5010
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
13,811✔
5011
                                    vcode_reg_t nlits)
5012
{
5013
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
204,400✔
5014
      if (other->args.items[0] == closure && other->args.items[1] == nlits)
27,753✔
5015
         return other->result;
×
5016
   }
5017

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

5021
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
13,811✔
5022
   vcode_add_arg(op, closure);
13,811✔
5023
   vcode_add_arg(op, nlits);
13,811✔
5024

5025
   return (op->result = vcode_add_reg(vtype_resolution(type),
13,811✔
5026
                                      VCODE_INVALID_STAMP));
5027
}
5028

5029
vcode_reg_t emit_closure(ident_t func, vcode_type_t rtype,
14,528✔
5030
                         const vcode_reg_t *args, int nargs)
5031
{
5032
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
208,014✔
5033
      if (other->func != func || other->args.count != nargs)
28,121✔
5034
         continue;
28,121✔
5035

5036
      bool match = true;
5037
      for (int i = 0; i < nargs; i++)
×
5038
         match &= other->args.items[i] == args[i];
×
5039

5040
      if (match)
×
5041
         return other->result;
×
5042
   }
5043

5044
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
14,528✔
5045
   op->func = func;
14,528✔
5046
   for (int i = 0; i < nargs; i++)
29,832✔
5047
      vcode_add_arg(op, args[i]);
15,304✔
5048

5049
   return (op->result = vcode_add_reg(vtype_closure(rtype),
14,528✔
5050
                                      VCODE_INVALID_STAMP));
5051
}
5052

5053
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
66,820✔
5054
{
5055
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
133,883✔
5056
      if (other->func == name)
57,018✔
5057
         return other->result;
26,565✔
5058
   }
5059

5060
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
40,255✔
5061
   op->func = name;
40,255✔
5062
   if (context != VCODE_INVALID_REG)
40,255✔
5063
      vcode_add_arg(op, context);
331✔
5064

5065
   VCODE_ASSERT(context == VCODE_INVALID_REG
40,255✔
5066
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5067
                "invalid protected init context argument");
5068
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
40,255✔
5069
                || active_unit->kind == VCODE_UNIT_PACKAGE
5070
                || active_unit->kind == VCODE_UNIT_THUNK,
5071
                "cannot use package init here");
5072
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
40,255✔
5073

5074
   return (op->result = vcode_add_reg(vtype_context(name),
40,255✔
5075
                                      VCODE_INVALID_STAMP));
5076
}
5077

5078
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
1,053✔
5079
                                vcode_reg_t path_name, vcode_reg_t inst_name)
5080
{
5081
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
1,053✔
5082
   vcode_add_arg(op, context);
1,053✔
5083
   op->func = vtype_name(type);
1,053✔
5084

5085
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
1,053✔
5086
      vcode_add_arg(op, path_name);
827✔
5087
      vcode_add_arg(op, inst_name);
827✔
5088

5089
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
827✔
5090
                   "path name argument must be uarray");
5091
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
827✔
5092
                   "inst name argument must be uarray");
5093
   }
5094

5095
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
1,053✔
5096
                "protected init type must be context");
5097
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
1,053✔
5098
                "invalid protected init context argument");
5099

5100
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
1,053✔
5101
}
5102

5103
void emit_process_init(vcode_reg_t closure, vcode_reg_t locus)
717✔
5104
{
5105
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
717✔
5106
   vcode_add_arg(op, closure);
717✔
5107
   vcode_add_arg(op, locus);
717✔
5108

5109
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
717✔
5110
                "closure argument to process init must be a closure");
5111
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
717✔
5112
                "locus argument to process init must be a debug locus");
5113
}
717✔
5114

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

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

5124
vcode_reg_t emit_context_upref(int hops)
34,072✔
5125
{
5126
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
236,068✔
5127
      if (other->hops == hops)
16,881✔
5128
         return other->result;
16,812✔
5129
   }
5130

5131
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
17,260✔
5132
   op->hops = hops;
17,260✔
5133

5134
   VCODE_ASSERT(hops >= 0, "invalid hop count");
17,260✔
5135

5136
   vcode_unit_t vu = active_unit;
17,260✔
5137
   for (int i = 0; i < hops; i++) {
28,321✔
5138
      vu = vu->context;
11,061✔
5139
      VCODE_ASSERT(vu, "hop count is greater than depth");
11,061✔
5140
   }
5141

5142
   return (op->result = vcode_add_reg(vtype_context(vu->name),
17,260✔
5143
                                      VCODE_INVALID_STAMP));
5144
}
5145

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

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

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

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

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

5169
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
59,165✔
5170
{
5171
   // Try scanning backwards through the block for another record ref
5172
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
4,525,109✔
5173
      if (other->args.items[0] == record && other->field == field)
817,683✔
5174
         return other->result;
6,752✔
5175
   }
5176

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

5181
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
52,413✔
5182

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

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

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

5192
   vcode_type_t field_type  = rtype->fields.items[field];
52,413✔
5193
   vcode_type_t result_type = field_type;
52,413✔
5194

5195
   const vtype_kind_t fkind = vtype_kind(field_type);
52,413✔
5196
   if (fkind == VCODE_TYPE_CARRAY)
52,413✔
5197
      result_type = vtype_elem(field_type);
7,257✔
5198
   else if (fkind == VCODE_TYPE_UARRAY)
5199
      result_type = field_type;
5200

5201
   op->result = vcode_add_reg(vtype_pointer(result_type), VCODE_INVALID_STAMP);
52,413✔
5202

5203
   return op->result;
52,413✔
5204
}
5205

5206
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
48,042✔
5207
{
5208
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
2,636,098✔
5209
      if (other->args.items[0] == array && other->args.items[1] == offset)
171,552✔
5210
         return other->result;
1,591✔
5211
   }
5212

5213
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
46,451✔
5214
   vcode_add_arg(op, array);
46,451✔
5215
   vcode_add_arg(op, offset);
46,451✔
5216

5217
   vcode_type_t rtype = vcode_reg_type(array);
46,451✔
5218
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
46,451✔
5219
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5220
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5221
                "argument to array ref must be a pointer or signal");
5222
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
46,451✔
5223
                "array ref offset argument must have offset type");
5224

5225
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
46,451✔
5226
}
5227

5228
vcode_reg_t emit_table_ref(vcode_reg_t array, vcode_reg_t stride,
890✔
5229
                           const vcode_reg_t *args, int nargs)
5230
{
5231
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_TABLE_REF) {
23,251✔
5232
      if (other->args.items[0] != array || other->args.items[1] != stride)
838✔
5233
         continue;
579✔
5234
      else if (other->args.count != nargs + 2)
259✔
5235
         continue;
×
5236

5237
      bool match = true;
5238
      for (int i = 0; i < nargs; i++)
636✔
5239
         match &= (other->args.items[i + 2] == args[i]);
377✔
5240

5241
      if (match)
259✔
5242
         return other->result;
33✔
5243
   }
5244

5245
   op_t *op = vcode_add_op(VCODE_OP_TABLE_REF);
857✔
5246
   vcode_add_arg(op, array);
857✔
5247
   vcode_add_arg(op, stride);
857✔
5248
   for (int i = 0; i < nargs; i++)
2,079✔
5249
      vcode_add_arg(op, args[i]);
1,222✔
5250

5251
   vcode_type_t rtype = vcode_reg_type(array);
857✔
5252
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER
857✔
5253
                && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY,
5254
                "argument to table ref must be a pointer or signal");
5255
   VCODE_ASSERT(vcode_reg_kind(stride) == VCODE_TYPE_OFFSET,
857✔
5256
                "table ref stride argument must have offset type");
5257

5258
   for (int i = 0; i < nargs; i++)
2,079✔
5259
      VCODE_ASSERT(vtype_is_integral(vcode_reg_type(args[i])),
1,222✔
5260
                   "table ref indices must be integral");
5261

5262
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
857✔
5263
}
5264

5265
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
54,053✔
5266
{
5267
   int64_t cconst;
54,053✔
5268
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
54,053✔
5269
       && cconst == 0)
39,734✔
5270
      return;
7,886✔
5271
   else if (dest == src)
52,746✔
5272
      return;
5273

5274
   op_t *op = vcode_add_op(VCODE_OP_COPY);
46,167✔
5275
   vcode_add_arg(op, dest);
46,167✔
5276
   vcode_add_arg(op, src);
46,167✔
5277
   if (count != VCODE_INVALID_REG)
46,167✔
5278
      vcode_add_arg(op, count);
43,723✔
5279

5280
   vcode_type_t dtype = vcode_reg_type(dest);
46,167✔
5281
   vcode_type_t stype = vcode_reg_type(src);
46,167✔
5282

5283
   vtype_kind_t dkind = vtype_kind(dtype);
46,167✔
5284
   vtype_kind_t skind = vtype_kind(stype);
46,167✔
5285

5286
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
46,167✔
5287
                "destination type is not a pointer or access");
5288
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
46,167✔
5289
                "source type is not a pointer or access");
5290
   VCODE_ASSERT(vtype_eq(dtype, stype),
46,167✔
5291
                "source and destination types do not match");
5292
   VCODE_ASSERT(count == VCODE_INVALID_REG
46,167✔
5293
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5294
                "count is not offset type");
5295

5296
   op->type = vtype_pointed(dtype);
46,167✔
5297
}
5298

5299
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
6,148✔
5300
{
5301
   VCODE_FOR_EACH_OP(other) {
85,883✔
5302
      if (other->kind == VCODE_OP_CLEAR_EVENT)
79,823✔
5303
         break;
5304
      else if (other->kind == VCODE_OP_SCHED_EVENT
79,759✔
5305
               && other->args.items[0] == nets
3,779✔
5306
               && other->args.items[1] == n_elems)
28✔
5307
         return;
5308
   }
5309

5310
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
6,124✔
5311
   vcode_add_arg(op, nets);
6,124✔
5312
   vcode_add_arg(op, n_elems);
6,124✔
5313

5314
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
6,124✔
5315
                "nets argument to sched event must be signal");
5316
}
5317

5318
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
741✔
5319
{
5320
   VCODE_FOR_EACH_OP(other) {
3,379✔
5321
      if (other->kind == VCODE_OP_SCHED_EVENT)
2,638✔
5322
         break;
5323
      else if (other->kind == VCODE_OP_CLEAR_EVENT
2,638✔
5324
               && other->args.items[0] == nets
52✔
5325
               && other->args.items[1] == n_elems)
×
5326
         return;
5327
   }
5328

5329
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
741✔
5330
   vcode_add_arg(op, nets);
741✔
5331
   vcode_add_arg(op, n_elems);
741✔
5332

5333
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
741✔
5334
                "nets argument to clear event must be signal");
5335
}
5336

5337
void emit_sched_active(vcode_reg_t nets, vcode_reg_t n_elems)
525✔
5338
{
5339
   op_t *op = vcode_add_op(VCODE_OP_SCHED_ACTIVE);
525✔
5340
   vcode_add_arg(op, nets);
525✔
5341
   vcode_add_arg(op, n_elems);
525✔
5342

5343
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
525✔
5344
                "nets argument to sched active must be signal");
5345
}
525✔
5346

5347
void emit_sched_process(vcode_reg_t delay)
7,149✔
5348
{
5349
   op_t *op = vcode_add_op(VCODE_OP_SCHED_PROCESS);
7,149✔
5350
   vcode_add_arg(op, delay);
7,149✔
5351

5352
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
7,149✔
5353
                "delay must have integer type");
5354
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
7,149✔
5355
                || active_unit->kind == VCODE_UNIT_PROCESS,
5356
                "sched process only allowed in process or procedure");
5357
}
7,149✔
5358

5359
void emit_resume(ident_t func)
1,163✔
5360
{
5361
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
1,163✔
5362
   op->func = func;
1,163✔
5363

5364
   block_t *b = &(active_unit->blocks.items[active_block]);
1,163✔
5365
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
1,163✔
5366
}
1,163✔
5367

5368
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
7,596✔
5369
{
5370
   int64_t lconst;
7,596✔
5371
   if (vcode_reg_const(len, &lconst) && lconst == 0)
7,596✔
5372
      return;
49✔
5373

5374
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
7,547✔
5375
   vcode_add_arg(op, ptr);
7,547✔
5376
   vcode_add_arg(op, value);
7,547✔
5377
   vcode_add_arg(op, len);
7,547✔
5378

5379
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
7,547✔
5380
                "target of memset must have pointer type");
5381
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
7,547✔
5382
                "value of memset must have scalar type");
5383
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
7,547✔
5384
                "length of memset must have offset type");
5385
}
5386

5387
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
1,915✔
5388
               const vcode_block_t *blocks, int ncases)
5389
{
5390
   int64_t cval1, cval2;
1,915✔
5391
   bool is_const = vcode_reg_const(value, &cval1);
1,915✔
5392

5393
   for (int i = 0; i < ncases; i++) {
9,491✔
5394
      bool can_fold = false;
7,576✔
5395
      if (cases[i] == value)
7,576✔
5396
         can_fold = true;
5397
      else if (is_const && vcode_reg_const(cases[i], &cval2))
7,576✔
5398
         can_fold = (cval1 == cval2);
×
5399

5400
      if (can_fold) {
×
5401
         emit_jump(blocks[i]);
×
5402
         return;
×
5403
      }
5404
   }
5405

5406
   if (is_const) {
1,915✔
5407
      emit_jump(def);
×
5408
      return;
×
5409
   }
5410

5411
   op_t *op = vcode_add_op(VCODE_OP_CASE);
1,915✔
5412
   vcode_add_arg(op, value);
1,915✔
5413
   vcode_add_target(op, def);
1,915✔
5414

5415
   for (int i = 0; i < ncases; i++) {
9,491✔
5416
      vcode_add_arg(op, cases[i]);
7,576✔
5417
      vcode_add_target(op, blocks[i]);
7,576✔
5418

5419
#ifdef DEBUG
5420
      for (int j = 0; j < i; j++)
28,212✔
5421
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
20,636✔
5422
#endif
5423
   }
5424
}
5425

5426
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
2,187✔
5427
                    vcode_reg_t kind, vcode_reg_t status)
5428
{
5429
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
2,187✔
5430
   vcode_add_arg(op, file);
2,187✔
5431
   vcode_add_arg(op, name);
2,187✔
5432
   vcode_add_arg(op, length);
2,187✔
5433
   vcode_add_arg(op, kind);
2,187✔
5434
   if (status != VCODE_INVALID_REG)
2,187✔
5435
      vcode_add_arg(op, status);
33✔
5436

5437
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
2,187✔
5438
                "file open first argument must have file pointer type");
5439
}
2,187✔
5440

5441
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
371✔
5442
{
5443
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
371✔
5444
   vcode_add_arg(op, file);
371✔
5445
   vcode_add_arg(op, value);
371✔
5446
   if (length != VCODE_INVALID_REG)
371✔
5447
      vcode_add_arg(op, length);
295✔
5448

5449
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
371✔
5450
                "file write first argument must have file pointer type");
5451
}
371✔
5452

5453
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
120✔
5454
                    vcode_reg_t inlen, vcode_reg_t outlen)
5455
{
5456
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
120✔
5457
   vcode_add_arg(op, file);
120✔
5458
   vcode_add_arg(op, ptr);
120✔
5459
   if (inlen != VCODE_INVALID_REG) {
120✔
5460
      vcode_add_arg(op, inlen);
56✔
5461
      if (outlen != VCODE_INVALID_REG)
56✔
5462
         vcode_add_arg(op, outlen);
44✔
5463
   }
5464

5465
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
120✔
5466
                "file read first argument must have file pointer type");
5467
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
120✔
5468
                "file read pointer argument must have pointer type");
5469
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
120✔
5470
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5471
                "file read outlen argument must have pointer type");
5472
}
120✔
5473

5474
vcode_reg_t emit_null(vcode_type_t type)
19,461✔
5475
{
5476
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
399,719✔
5477
      if (vtype_eq(vcode_reg_type(other->result), type))
11,586✔
5478
         return other->result;
5,957✔
5479
   }
5480

5481
   op_t *op = vcode_add_op(VCODE_OP_NULL);
13,504✔
5482
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
13,504✔
5483

5484
   vtype_kind_t kind = vtype_kind(type);
13,504✔
5485
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
13,504✔
5486
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5487
                "null type must be file, access, context, or pointer");
5488

5489
   return op->result;
5490
}
5491

5492
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
1,037✔
5493
{
5494
   op_t *op = vcode_add_op(VCODE_OP_NEW);
1,037✔
5495
   if (length != VCODE_INVALID_REG)
1,037✔
5496
      vcode_add_arg(op, length);
915✔
5497

5498
   op->result = vcode_add_reg(vtype_access(type), VCODE_INVALID_STAMP);
1,037✔
5499

5500
   vtype_kind_t kind = vtype_kind(type);
1,037✔
5501
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
1,037✔
5502
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5503
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5504
                "new type must be int, real, record, access, or uarray");
5505
   VCODE_ASSERT(length == VCODE_INVALID_REG
1,037✔
5506
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5507
                "new length must have offset type");
5508

5509
   return op->result;
1,037✔
5510
}
5511

5512
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
4,110✔
5513
{
5514
   VCODE_FOR_EACH_OP(other) {
168,510✔
5515
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
165,456✔
5516
         return;
5517
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
164,845✔
5518
         return;
5519
   }
5520

5521
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
3,054✔
5522
   vcode_add_arg(op, ptr);
3,054✔
5523
   vcode_add_arg(op, locus);
3,054✔
5524

5525
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
3,054✔
5526
                "null check argument must be an access");
5527
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
3,054✔
5528
                "locus argument to null check must be a debug locus");
5529
}
5530

5531
void emit_deallocate(vcode_reg_t ptr)
477✔
5532
{
5533
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
477✔
5534
   vcode_add_arg(op, ptr);
477✔
5535

5536
   vcode_type_t ptype = vcode_reg_type(ptr);
477✔
5537
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
477✔
5538
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5539
                "deallocate argument must be pointer to access");
5540
}
477✔
5541

5542
vcode_reg_t emit_all(vcode_reg_t reg)
5,147✔
5543
{
5544
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
238,851✔
5545
      if (other->args.items[0] == reg)
14,384✔
5546
         return other->result;
1,056✔
5547
   }
5548

5549
   op_t *op = vcode_add_op(VCODE_OP_ALL);
4,091✔
5550
   vcode_add_arg(op, reg);
4,091✔
5551

5552
   vcode_type_t vtype = vcode_reg_type(reg);
4,091✔
5553

5554
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
4,091✔
5555
                "all argument must be an access");
5556

5557
   vcode_type_t pointed = vtype_pointed(vtype);
4,091✔
5558
   op->result = vcode_add_reg(vtype_pointer(pointed), vcode_reg_stamp(reg));
4,091✔
5559

5560
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
4,091✔
5561
                "cannot dereference opaque type");
5562

5563
   return op->result;
5564
}
5565

5566
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
18,392✔
5567
{
5568
   block_t *b = &(active_unit->blocks.items[active_block]);
18,392✔
5569
   for (int i = b->ops.count - 1; i >= 0; i--) {
435,097✔
5570
      const op_t *other = &(b->ops.items[i]);
417,452✔
5571
      if (other->kind == kind && other->args.items[0] == sig)
417,452✔
5572
         return other->result;
747✔
5573
   }
5574

5575
   op_t *op = vcode_add_op(kind);
17,645✔
5576
   vcode_add_arg(op, sig);
17,645✔
5577

5578
   vcode_type_t stype = vcode_reg_type(sig);
17,645✔
5579
   op->type = stype;
17,645✔
5580

5581
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
17,645✔
5582
                "argument r%d to resolved is not a signal", sig);
5583

5584
   vcode_type_t rtype = vtype_base(stype);
17,645✔
5585

5586
   const vtype_kind_t rkind = vtype_kind(rtype);
17,645✔
5587
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
17,645✔
5588
      rtype = vtype_elem(rtype);
×
5589

5590
   VCODE_ASSERT(vtype_is_scalar(rtype),
17,645✔
5591
                "resolved signal base type must be scalar");
5592

5593
   op->result = vcode_add_reg(vtype_pointer(rtype), vcode_reg_stamp(sig));
17,645✔
5594

5595
   return op->result;
17,645✔
5596
}
5597

5598
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
18,131✔
5599
{
5600
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
18,131✔
5601
}
5602

5603
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
261✔
5604
{
5605
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
261✔
5606
}
5607

5608
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
56✔
5609
{
5610
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
56✔
5611
   vcode_add_arg(op, signal);
56✔
5612
   if (len != VCODE_INVALID_REG)
56✔
5613
      vcode_add_arg(op, len);
12✔
5614

5615
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
56✔
5616
                "signal argument to last event must have signal type");
5617
   VCODE_ASSERT(len == VCODE_INVALID_REG
56✔
5618
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5619
                "length argument to last event must have offset type");
5620

5621
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
56✔
5622
}
5623

5624
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
60✔
5625
{
5626
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
60✔
5627
   vcode_add_arg(op, signal);
60✔
5628
   if (len != VCODE_INVALID_REG)
60✔
5629
      vcode_add_arg(op, len);
8✔
5630

5631
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
60✔
5632
                "signal argument to last active must have signal type");
5633
   VCODE_ASSERT(len == VCODE_INVALID_REG
60✔
5634
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5635
                "length argument to last active must have offset type");
5636

5637
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
60✔
5638
}
5639

5640
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
7,430✔
5641
{
5642
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
7,430✔
5643
   vcode_add_arg(op, signal);
7,430✔
5644
   vcode_add_arg(op, locus);
7,430✔
5645

5646
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
7,430✔
5647
                "signal argument must have signal type");
5648
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
7,430✔
5649
                "locus argument must have debug locus type");
5650
}
7,430✔
5651

5652
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
48✔
5653
{
5654
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
48✔
5655
   vcode_add_arg(op, signal);
48✔
5656
   vcode_add_arg(op, len);
48✔
5657

5658
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
48✔
5659
                "signal argument to last active must have signal type");
5660
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
48✔
5661
                "length argument to last active must have offset type");
5662

5663
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
48✔
5664
}
5665

5666
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
436✔
5667
{
5668
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
436✔
5669
   vcode_add_arg(op, signal);
436✔
5670
   vcode_add_arg(op, len);
436✔
5671

5672
   vcode_type_t signal_type = vcode_reg_type(signal);
436✔
5673

5674
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
436✔
5675
                "signal argument to driving value must have signal type");
5676
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
436✔
5677
                "length argument to driving value must have offset type");
5678

5679
   vcode_type_t base_type = vtype_base(signal_type);
436✔
5680
   op->result = vcode_add_reg(vtype_pointer(base_type), VCODE_INVALID_STAMP);
436✔
5681

5682
   return op->result;
436✔
5683
}
5684

5685
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
61,476✔
5686
                       vcode_reg_t dim)
5687
{
5688
   if (rlen == llen)
61,476✔
5689
      return;
5690

5691
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
290,224✔
5692
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
4,020✔
5693
         return;
5694
   }
5695

5696
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
9,823✔
5697
   vcode_add_arg(op, llen);
9,823✔
5698
   vcode_add_arg(op, rlen);
9,823✔
5699
   vcode_add_arg(op, locus);
9,823✔
5700
   if (dim != VCODE_INVALID_REG)
9,823✔
5701
      vcode_add_arg(op, dim);
48✔
5702

5703
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
9,823✔
5704
                "locus argument to length check must be a debug locus");
5705
}
5706

5707
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
233✔
5708
{
5709
   int64_t cval;
233✔
5710
   if (vcode_reg_const(exp, &cval) && cval >= 0)
233✔
5711
      return;
73✔
5712

5713
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
2,119✔
5714
      if (other->args.items[0] == exp)
20✔
5715
         return;
5716
   }
5717

5718
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
160✔
5719
   vcode_add_arg(op, exp);
160✔
5720
   vcode_add_arg(op, locus);
160✔
5721

5722
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
160✔
5723
                "exp argument to exponent check must be a integer");
5724
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
160✔
5725
                "locus argument to exponent check must be a debug locus");
5726
}
5727

5728
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
4,083✔
5729
{
5730
   int64_t cval;
4,083✔
5731
   if (vcode_reg_const(denom, &cval) && cval != 0)
4,083✔
5732
      return;
3,963✔
5733

5734
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
3,124✔
5735
      if (other->args.items[0] == denom)
64✔
5736
         return;
5737
   }
5738

5739
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
120✔
5740
   vcode_add_arg(op, denom);
120✔
5741
   vcode_add_arg(op, locus);
120✔
5742

5743
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
120✔
5744
                "denom argument to zero check must be a integer");
5745
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
120✔
5746
                "locus argument to zero check must be a debug locus");
5747
}
5748

5749
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
146,349✔
5750
                                   vcode_reg_t right, vcode_reg_t dir)
5751
{
5752
   int64_t dconst;
146,349✔
5753
   if (!vcode_reg_const(dir, &dconst))
146,349✔
5754
      return false;
5755

5756
   int64_t lconst, rconst;
132,569✔
5757
   if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
132,569✔
5758
      const bool is_null = (dconst == RANGE_TO && lconst > rconst)
99,374✔
5759
         || (dconst == RANGE_DOWNTO && rconst > lconst);
203,097✔
5760

5761
      int64_t low, high;
103,724✔
5762
      if (vcode_reg_bounds(reg, &low, &high)) {
103,724✔
5763
         const bool ok_static =
207,448✔
5764
            (dconst == RANGE_TO && low >= lconst && high <= rconst)
99,374✔
5765
            || (dconst == RANGE_DOWNTO && low >= rconst && high <= lconst)
11,968✔
5766
            || (!is_null && (reg == left || reg == right));
111,792✔
5767

5768
         return ok_static;
103,724✔
5769
      }
5770
   }
5771
   else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
28,845✔
5772
      vstamp_t *lbounds = vcode_stamp_data(vcode_reg_data(left)->stamp);
25,899✔
5773
      vstamp_t *rbounds = vcode_stamp_data(vcode_reg_data(right)->stamp);
25,899✔
5774

5775
      assert(lbounds->kind == VCODE_STAMP_REAL);
25,899✔
5776
      assert(rbounds->kind == VCODE_STAMP_REAL);
25,899✔
5777

5778
      double low, high;
25,899✔
5779

5780
      reg_t *rr = vcode_reg_data(reg);
25,899✔
5781
      vstamp_t *bounds = vcode_stamp_data(rr->stamp);
25,899✔
5782
      if (bounds != NULL) {
25,899✔
5783
         assert(bounds->kind == VCODE_STAMP_REAL);
17,033✔
5784
         low = bounds->u.real.low;
17,033✔
5785
         high = bounds->u.real.high;
17,033✔
5786
      }
5787
      else {
5788
         vtype_t *type = vcode_type_data(rr->type);
8,866✔
5789
         assert(type->kind == VCODE_TYPE_REAL);
8,866✔
5790
         low = type->rlow;
8,866✔
5791
         high = type->rhigh;
8,866✔
5792
      }
5793

5794
      if (isfinite(low) && lbounds->u.real.low == -DBL_MAX
25,899✔
5795
          && isfinite(high) && rbounds->u.real.high == DBL_MAX) {
24,949✔
5796
         // Covers the complete double range so can never overflow
5797
         return true;
24,949✔
5798
      }
5799
   }
5800

5801
   return false;
5802
}
5803

5804
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
147,558✔
5805
                              vcode_reg_t left, vcode_reg_t right,
5806
                              vcode_reg_t dir, vcode_reg_t locus,
5807
                              vcode_reg_t hint)
5808
{
5809
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
7,330,840✔
5810
      if (other->args.items[0] == reg && other->args.items[1] == left
26,422✔
5811
          && other->args.items[2] == right && other->args.items[3] == dir)
1,496✔
5812
         return;
5813
   }
5814

5815
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
146,349✔
5816
      emit_comment("Elided bounds check for r%d", reg);
120,605✔
5817
      return;
120,605✔
5818
   }
5819

5820
   op_t *op = vcode_add_op(kind);
25,744✔
5821
   vcode_add_arg(op, reg);
25,744✔
5822
   vcode_add_arg(op, left);
25,744✔
5823
   vcode_add_arg(op, right);
25,744✔
5824
   vcode_add_arg(op, dir);
25,744✔
5825
   vcode_add_arg(op, locus);
25,744✔
5826
   vcode_add_arg(op, hint);
25,744✔
5827

5828
   VCODE_ASSERT(vtype_is_numeric(vcode_reg_type(reg)),
25,744✔
5829
                "argument to bounds check must be numeric");
5830
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
25,744✔
5831
                "locus argument to bounds check must be a debug locus");
5832
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
25,744✔
5833
                "hint argument to bounds check must be a debug locus");
5834
}
5835

5836
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
30,492✔
5837
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5838
{
5839
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
30,492✔
5840
}
30,492✔
5841

5842
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
117,066✔
5843
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5844
{
5845
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
117,066✔
5846
}
117,066✔
5847

5848
void emit_dir_check(vcode_reg_t reg, vcode_reg_t dir, vcode_reg_t locus)
4,528✔
5849
{
5850
   if (reg == dir)
4,528✔
5851
      return;
5852

5853
   op_t *op = vcode_add_op(VCODE_OP_DIR_CHECK);
3,283✔
5854
   vcode_add_arg(op, reg);
3,283✔
5855
   vcode_add_arg(op, dir);
3,283✔
5856
   vcode_add_arg(op, locus);
3,283✔
5857

5858
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
3,283✔
5859
                "locus argument to dir check must be a debug locus");
5860
}
5861

5862
void emit_package_scope(vcode_reg_t locus)
72✔
5863
{
5864
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
72✔
5865
   vcode_add_arg(op, locus);
72✔
5866

5867
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
72✔
5868
                "locus argument to package scope must be a debug locus");
5869
}
72✔
5870

5871
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
1,103✔
5872
{
5873
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
1,103✔
5874
   vcode_add_arg(op, locus);
1,103✔
5875
   op->type = type;
1,103✔
5876

5877
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,103✔
5878
                "locus argument to array scope must be a debug locus");
5879
}
1,103✔
5880

5881
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
2,968✔
5882
{
5883
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
2,968✔
5884
   vcode_add_arg(op, locus);
2,968✔
5885
   op->type = type;
2,968✔
5886

5887
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,968✔
5888
                "locus argument to record scope must be a debug locus");
5889
}
2,968✔
5890

5891
void emit_pop_scope(void)
4,143✔
5892
{
5893
   vcode_add_op(VCODE_OP_POP_SCOPE);
4,143✔
5894
}
4,143✔
5895

5896
vcode_reg_t emit_debug_locus(object_t *obj)
276,442✔
5897
{
5898
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
11,750,156✔
5899
      if (other->object == obj)
1,451,954✔
5900
         return other->result;
30,111✔
5901
   }
5902

5903
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
246,331✔
5904
   op->object = obj;
246,331✔
5905
   op->result = vcode_add_reg(vtype_debug_locus(), VCODE_INVALID_STAMP);
246,331✔
5906

5907
   return op->result;
246,331✔
5908
}
5909

5910
void emit_debug_out(vcode_reg_t reg)
×
5911
{
5912
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
5913
   vcode_add_arg(op, reg);
×
5914
}
×
5915

5916
void emit_cover_stmt(vcode_reg_t counters, uint32_t tag)
1,637✔
5917
{
5918
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,637✔
5919
   vcode_add_arg(op, counters);
1,637✔
5920
   op->tag = tag;
1,637✔
5921

5922
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
1,637✔
5923
                "counters argument must be pointer");
5924
}
1,637✔
5925

5926
void emit_cover_branch(vcode_reg_t counters, uint32_t tag)
695✔
5927
{
5928
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
695✔
5929
   vcode_add_arg(op, counters);
695✔
5930
   op->tag = tag;
695✔
5931

5932
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
695✔
5933
                "counters argument must be pointer");
5934
}
695✔
5935

5936
void emit_cover_toggle(vcode_reg_t signal, vcode_reg_t count, uint32_t tag)
1,364✔
5937
{
5938
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
1,364✔
5939
   vcode_add_arg(op, signal);
1,364✔
5940
   vcode_add_arg(op, count);
1,364✔
5941
   op->tag = tag;
1,364✔
5942
}
1,364✔
5943

5944
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
18✔
5945
{
5946
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
18✔
5947
   vcode_add_arg(op, signal);
18✔
5948
   vcode_add_arg(op, low);
18✔
5949
   op->tag = tag;
18✔
5950
}
18✔
5951

5952
void emit_cover_expr(vcode_reg_t counters, uint32_t tag)
1,144✔
5953
{
5954
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
1,144✔
5955
   vcode_add_arg(op, counters);
1,144✔
5956
   op->tag = tag;
1,144✔
5957

5958
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
1,144✔
5959
                "counters argument must be pointer");
5960
}
1,144✔
5961

5962
void emit_unreachable(vcode_reg_t locus)
2,022✔
5963
{
5964
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
2,022✔
5965
   if (locus != VCODE_INVALID_REG)
2,022✔
5966
      vcode_add_arg(op, locus);
175✔
5967
}
2,022✔
5968

5969
vcode_reg_t emit_undefined(vcode_type_t type, vcode_stamp_t stamp)
34✔
5970
{
5971
   active_unit->flags |= UNIT_UNDEFINED;
34✔
5972

5973
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
34✔
5974
   op->result = vcode_add_reg(type, stamp);
34✔
5975

5976
   return op->result;
34✔
5977
}
5978

5979
void emit_debug_info(const loc_t *loc)
4,620,340✔
5980
{
5981
   if (!loc_invalid_p(loc))
4,620,340✔
5982
      vcode_block_data()->last_loc = *loc;
4,588,795✔
5983
}
4,620,340✔
5984

5985
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
13,937✔
5986
{
5987
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
517,811✔
5988
      if (other->args.items[0] == context && other->ident == name)
18,803✔
5989
         return other->result;
6,673✔
5990
   }
5991

5992
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
7,264✔
5993
   vcode_add_arg(op, context);
7,264✔
5994
   op->ident = name;
7,264✔
5995

5996
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
7,264✔
5997
                "first argument to link var must be context");
5998

5999
   vcode_stamp_t stamp = VCODE_INVALID_STAMP;
7,264✔
6000

6001
   if (vtype_kind(type) == VCODE_TYPE_CARRAY)
7,264✔
6002
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)), stamp);
806✔
6003
   else
6004
      op->result = vcode_add_reg(vtype_pointer(type), stamp);
6,458✔
6005

6006
   return op->result;
7,264✔
6007
}
6008

6009
vcode_reg_t emit_link_package(ident_t name)
17,407✔
6010
{
6011
   VCODE_FOR_EACH_OP(other) {
629,945✔
6012
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
620,907✔
6013
         return other->result;
7,803✔
6014
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
613,104✔
6015
         return other->result;
566✔
6016
   }
6017

6018
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
9,038✔
6019
   op->ident = name;
9,038✔
6020

6021
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
9,038✔
6022

6023
   vcode_type_t type = vtype_context(name);
9,038✔
6024
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
9,038✔
6025
}
6026

6027
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
1,176✔
6028
{
6029
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
2,896✔
6030
      if (other->args.items[0] == state)
×
6031
         return;
6032
   }
6033

6034
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
1,176✔
6035
   vcode_add_arg(op, state);
1,176✔
6036
   if (strong != VCODE_INVALID_REG)
1,176✔
6037
      vcode_add_arg(op, strong);
48✔
6038

6039
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
1,176✔
6040
                "state must have integer type");
6041
   VCODE_ASSERT(strong == VCODE_INVALID_REG
1,176✔
6042
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
6043
                "strong argument not is not boolean");
6044
}
6045

6046
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
68✔
6047
                               vcode_reg_t locus, vcode_reg_t bounds)
6048
{
6049
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
68✔
6050
   vcode_add_arg(op, value);
68✔
6051
   vcode_add_arg(op, context);
68✔
6052
   vcode_add_arg(op, locus);
68✔
6053
   if (bounds != VCODE_INVALID_REG)
68✔
6054
      vcode_add_arg(op, bounds);
8✔
6055

6056
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
68✔
6057
                "invalid reflect value context argument");
6058
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
68✔
6059
                "locus argument to reflect value must be a debug locus");
6060

6061
   vcode_type_t type = vtype_access(vtype_opaque());
68✔
6062
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
68✔
6063
}
6064

6065
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
68✔
6066
                                 vcode_reg_t bounds)
6067
{
6068
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
68✔
6069
   vcode_add_arg(op, context);
68✔
6070
   vcode_add_arg(op, locus);
68✔
6071
   if (bounds != VCODE_INVALID_REG)
68✔
6072
      vcode_add_arg(op, bounds);
12✔
6073

6074
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
68✔
6075
                "invalid reflect value context argument");
6076
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
68✔
6077
                "locus argument to reflect value must be a debug locus");
6078

6079
   vcode_type_t type = vtype_access(vtype_opaque());
68✔
6080
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
68✔
6081
}
6082

6083
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
364✔
6084
                                  int nargs)
6085
{
6086
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
364✔
6087
   op->func = func;
364✔
6088

6089
   for (int i = 0; i < nargs; i++)
852✔
6090
      vcode_add_arg(op, args[i]);
488✔
6091

6092
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
364✔
6093
}
6094

6095
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
45✔
6096
{
6097
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
45✔
6098
   vcode_add_arg(op, left);
45✔
6099
   vcode_add_arg(op, right);
45✔
6100

6101
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
45✔
6102
                "or trigger left argument must be trigger");
6103
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
45✔
6104
                "or trigger right argument must be trigger");
6105

6106
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
45✔
6107
}
6108

6109
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
86✔
6110
{
6111
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
86✔
6112
   vcode_add_arg(op, left);
86✔
6113
   vcode_add_arg(op, right);
86✔
6114

6115
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
86✔
6116
                "cmp trigger left argument must be signal");
6117
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
86✔
6118
                "cmp trigger right argument must be integer");
6119

6120
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
86✔
6121
}
6122

6123
void emit_add_trigger(vcode_reg_t trigger)
509✔
6124
{
6125
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
509✔
6126
   vcode_add_arg(op, trigger);
509✔
6127

6128
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
509✔
6129
                "add trigger argument must be trigger");
6130
}
509✔
6131

6132
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
259✔
6133
                               vcode_type_t type, vcode_stamp_t stamp,
6134
                               const vcode_reg_t *args, int nargs)
6135
{
6136
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
259✔
6137
   op->type  = type;
259✔
6138
   op->ident = scope;
259✔
6139
   vcode_add_arg(op, locus);
259✔
6140
   for (int i = 0; i < nargs; i++)
299✔
6141
      vcode_add_arg(op, args[i]);
40✔
6142

6143
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
259✔
6144
                "bind external argument must be locus");
6145

6146
   op->result = vcode_add_reg(vtype_pointer(type), VCODE_INVALID_STAMP);
259✔
6147
   vcode_reg_data(op->result)->stamp = stamp;
259✔
6148
   return op->result;
259✔
6149
}
6150

6151
void emit_put_driver(vcode_reg_t target, vcode_reg_t count, vcode_reg_t values)
671✔
6152
{
6153
   op_t *op = vcode_add_op(VCODE_OP_PUT_DRIVER);
671✔
6154
   vcode_add_arg(op, target);
671✔
6155
   vcode_add_arg(op, count);
671✔
6156
   vcode_add_arg(op, values);
671✔
6157

6158
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
671✔
6159
                "put driver target is not signal");
6160
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
671✔
6161
                "put driver count is not offset type");
6162
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
671✔
6163
                "signal cannot be values argument for put driver");
6164
}
671✔
6165

6166
void emit_deposit_signal(vcode_reg_t target, vcode_reg_t count,
33✔
6167
                         vcode_reg_t values)
6168
{
6169
   op_t *op = vcode_add_op(VCODE_OP_DEPOSIT_SIGNAL);
33✔
6170
   vcode_add_arg(op, target);
33✔
6171
   vcode_add_arg(op, count);
33✔
6172
   vcode_add_arg(op, values);
33✔
6173

6174
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
33✔
6175
                "deposit signal target is not signal");
6176
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
33✔
6177
                "deposit signal count is not offset type");
6178
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
33✔
6179
                "signal cannot be values argument for deposit signal");
6180
}
33✔
6181

6182
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
1,531✔
6183
{
6184
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
1,531✔
6185
   vcode_add_arg(op, spec);
1,531✔
6186
   vcode_add_arg(op, length);
1,531✔
6187
   if (locus != VCODE_INVALID_REG)
1,531✔
6188
      vcode_add_arg(op, locus);
1,305✔
6189

6190
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
1,531✔
6191
                "spec argument to bind foreign must be a pointer");
6192
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
1,531✔
6193
                "length argument to bind foreign must be offset");
6194
   VCODE_ASSERT(locus == VCODE_INVALID_REG
1,531✔
6195
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6196
                "locus argument to bind foreign value must be a debug locus");
6197
}
1,531✔
6198

6199
vcode_reg_t emit_instance_name(vcode_reg_t kind)
7,320✔
6200
{
6201
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
7,320✔
6202
   vcode_add_arg(op, kind);
7,320✔
6203

6204
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
7,320✔
6205
                "kind argument to instance name must be offset");
6206

6207
   vcode_type_t type = vtype_uarray(1, vtype_char());
7,320✔
6208
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
7,320✔
6209
}
6210

6211
vcode_reg_t emit_get_counters(ident_t block)
1,070✔
6212
{
6213
   op_t *op = vcode_add_op(VCODE_OP_GET_COUNTERS);
1,070✔
6214
   op->ident = block;
1,070✔
6215

6216
   vcode_type_t vint32 = vtype_int(INT32_MIN, INT32_MAX);
1,070✔
6217
   vcode_type_t type = vtype_pointer(vint32);
1,070✔
6218
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
1,070✔
6219
}
6220

6221
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
14,606✔
6222
{
6223
   vcode_state_t state;
14,606✔
6224
   vcode_state_save(&state);
14,606✔
6225

6226
   vcode_select_unit(vu);
14,606✔
6227

6228
   const int nblocks = vcode_count_blocks();
14,606✔
6229
   for (int i = 0; i < nblocks; i++) {
36,680✔
6230
      vcode_select_block(i);
22,074✔
6231

6232
      const int nops = vcode_count_ops();
22,074✔
6233
      for (int op = 0; op < nops; op++) {
437,869✔
6234
         switch (vcode_get_op(op)) {
415,795✔
6235
         case VCODE_OP_LINK_PACKAGE:
518✔
6236
            (*fn)(vcode_get_ident(op), ctx);
518✔
6237
            break;
518✔
6238
         case VCODE_OP_FCALL:
16,111✔
6239
         case VCODE_OP_PCALL:
6240
         case VCODE_OP_CLOSURE:
6241
         case VCODE_OP_PROTECTED_INIT:
6242
         case VCODE_OP_PACKAGE_INIT:
6243
         case VCODE_OP_FUNCTION_TRIGGER:
6244
            (*fn)(vcode_get_func(op), ctx);
16,111✔
6245
            break;
16,111✔
6246
         default:
6247
            break;
6248
         }
6249
      }
6250
   }
6251

6252
   vcode_state_restore(&state);
14,606✔
6253
}
14,606✔
6254

6255
#if VCODE_CHECK_UNIONS
6256
#define OP_USE_COUNT_U0(x)                                              \
6257
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6258
#define OP_USE_COUNT_U1(x)                                              \
6259
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6260
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6261
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6262

6263
__attribute__((constructor))
6264
static void vcode_check_unions(void)
6265
{
6266
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6267
   for (int i = 0; i < 256; i++) {
6268
      assert(OP_USE_COUNT_U0(i) <= 1);
6269
      assert(OP_USE_COUNT_U1(i) <= 1);
6270
   }
6271
}
6272
#endif  // VCODE_CHECK_UNIONS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc