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

nickg / nvc / 23707913150

29 Mar 2026 11:20AM UTC coverage: 92.381% (-0.03%) from 92.415%
23707913150

push

github

nickg
Add operation to wait on signal becoming active

91 of 94 new or added lines in 7 files covered. (96.81%)

627 existing lines in 13 files now uncovered.

76944 of 83290 relevant lines covered (92.38%)

586423.94 hits per line

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

97.07
/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);
15,572,787✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_block);
465,142✔
38
DECLARE_AND_DEFINE_ARRAY(vcode_type);
124,642✔
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);
17,009,262✔
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);
41,118✔
179
DECLARE_AND_DEFINE_ARRAY(var);
735,443✔
180
DECLARE_AND_DEFINE_ARRAY(reg);
13,007,419✔
181
DECLARE_AND_DEFINE_ARRAY(block);
191,315✔
182
DECLARE_AND_DEFINE_ARRAY(vtype);
33,354,346✔
183
DECLARE_AND_DEFINE_ARRAY(vstamp);
2,078,391✔
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)
55,744✔
239
{
240
   int64_t result;
55,744✔
241
   if (__builtin_add_overflow(a, b, &result))
55,744✔
242
      return b < 0 ? INT64_MIN : INT64_MAX;
14,389✔
243

244
   return result;
245
}
246

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

253
   return result;
254
}
255

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

262
   return result;
263
}
264

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

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

275
   return reg;
2,073,763✔
276
}
277

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

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

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

294
   block_t *block = vcode_block_data();
2,691,813✔
295

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

302
   return op;
2,691,813✔
303
}
304

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

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

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

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

324
static op_t *vcode_find_definition(vcode_reg_t reg)
2,802,095✔
325
{
326
   for (int i = active_block; i >= 0; i--) {
2,840,310✔
327
      block_t *b = &(active_unit->blocks.items[i]);
2,838,745✔
328
      for (int j = b->ops.count - 1; j >= 0; j--) {
56,940,678✔
329
         if (b->ops.items[j].result == reg)
56,902,463✔
330
            return &(b->ops.items[j]);
2,800,530✔
331
      }
332
   }
333

334
   return NULL;
335
}
336

337
#ifdef DEBUG
338
static void vcode_assert_const(vcode_reg_t reg, const char *what)
2,781,096✔
339
{
340
   op_t *defn = vcode_find_definition(reg);
2,781,096✔
341
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
2,781,096✔
342
                what, reg);
343
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
2,781,096✔
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
}
2,781,096✔
352
#endif
353

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

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

367
   int depth = MASK_CONTEXT(type);
8,240,621✔
368
   assert(depth <= unit->depth);
8,240,621✔
369
   while (depth != unit->depth)
9,445,241✔
370
      unit = unit->context;
1,204,620✔
371

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

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

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

383
   int depth = MASK_CONTEXT(stamp);
1,592,071✔
384
   assert(depth <= unit->depth);
1,592,071✔
385
   while (depth != unit->depth)
1,634,033✔
386
      unit = unit->context;
41,962✔
387

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

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

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

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

407
   switch (defn->kind) {
19,434✔
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,720✔
429
      vcode_var_data(defn->address)->flags |= VAR_HEAP;
1,720✔
430
      break;
1,720✔
431

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

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

441
         vcode_select_unit(vu);
811✔
442

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

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

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

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

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

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

468
         // Any store to this variable must be heap allocated
469
         for (int i = 0; i < active_unit->blocks.count; i++) {
22,823✔
470
            block_t *b = &(active_unit->blocks.items[i]);
21,419✔
471
            for (int j = 0; j < b->ops.count; j++) {
293,675✔
472
               op_t *op = &(b->ops.items[j]);
272,256✔
473
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
272,256✔
474
                  vcode_heap_allocate(op->args.items[0]);
1,404✔
475

476
               VCODE_ASSERT(
272,256✔
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++) {
7,705✔
486
         const vtype_kind_t rkind = vcode_reg_kind(reg);
5,719✔
487
         if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
5,719✔
488
            // Function may return a pointer to its argument
489
            vcode_heap_allocate(defn->args.items[i]);
5,581✔
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:
UNCOV
554
      VCODE_ASSERT(false, "cannot heap allocate r%d", reg);
×
555
   }
556
}
557

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

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

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

574
   if (unit == active_unit)
74,223✔
575
      vcode_close();
14,264✔
576

577
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
92,594✔
578
      assert(it->context == unit);
18,371✔
579
      it->context = NULL;
18,371✔
580
   }
581
   unit->children = NULL;
74,223✔
582

583
   if (unit->context != NULL) {
74,223✔
584
      vcode_unit_t *it = &(unit->context->children);
19,972✔
585
      for (; *it != NULL && *it != unit; it = &((*it)->next))
53,305✔
586
         ;
587
      assert(*it != NULL);
19,972✔
588
      *it = (*it)->next;
19,972✔
589
   }
590

591
   for (unsigned i = 0; i < unit->blocks.count; i++) {
265,512✔
592
      block_t *b = &(unit->blocks.items[i]);
191,289✔
593

594
      for (unsigned j = 0; j < b->ops.count; j++) {
2,768,806✔
595
         op_t *o = &(b->ops.items[j]);
2,577,517✔
596
         if (OP_HAS_COMMENT(o->kind))
2,577,517✔
597
            free(o->comment);
297,470✔
598
         if (OP_HAS_TARGET(o->kind))
2,577,517✔
599
            free(o->targets.items);
109,390✔
600
         free(o->args.items);
2,577,517✔
601
      }
602
      free(b->ops.items);
191,289✔
603
   }
604
   free(unit->blocks.items);
74,223✔
605

606
   for (unsigned i = 0; i < unit->types.count; i++) {
559,391✔
607
      vtype_t *vt = &(unit->types.items[i]);
485,168✔
608
      if (vt->kind == VCODE_TYPE_RECORD)
485,168✔
609
         free(vt->fields.items);
8,842✔
610
   }
611
   free(unit->types.items);
74,223✔
612

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

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

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

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

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

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

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

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

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

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

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

663
   if (s->u.intg.low == s->u.intg.high) {
939,205✔
664
      if (value) *value = s->u.intg.low;
724,707✔
665
      return true;
724,707✔
666
   }
667
   else
668
      return false;
669
}
670

671
bool vcode_reg_bounds(vcode_reg_t reg, int64_t *low, int64_t *high)
562,469✔
672
{
673
   reg_t *r = vcode_reg_data(reg);
562,469✔
674
   if (r->stamp == VCODE_INVALID_STAMP) {
562,469✔
675
      vtype_t *t = vcode_type_data(r->type);
100,308✔
676
      if (t->kind == VCODE_TYPE_INT || t->kind == VCODE_TYPE_OFFSET) {
100,308✔
677
         *low = t->low;
98,927✔
678
         *high = t->high;
98,927✔
679
         return true;
98,927✔
680
      }
681
   }
682
   else {
683
      vstamp_t *s = vcode_stamp_data(r->stamp);
462,161✔
684
      if (s->kind == VCODE_STAMP_INT) {
462,161✔
685
         *low = s->u.intg.low;
461,621✔
686
         *high = s->u.intg.high;
461,621✔
687
         return true;
461,621✔
688
      }
689
   }
690

691
   return false;
692
}
693

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

714
   return false;
715
}
716

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

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

723
   int pruned = 0;
74,249✔
724
   do {
105,365✔
725
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
105,365✔
726
      pruned = 0;
105,365✔
727

728
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
419,523✔
729
         block_t *b = &(active_unit->blocks.items[i]);
314,158✔
730

731
         for (int j = b->ops.count - 1; j >= 0; j--) {
5,085,506✔
732
            op_t *o = &(b->ops.items[j]);
4,771,348✔
733

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

796
            default:
797
               break;
798
            }
799

800
            for (int k = 0; k < o->args.count; k++) {
14,204,898✔
801
               if (o->args.items[k] != VCODE_INVALID_REG)
9,433,550✔
802
                  uses[o->args.items[k]]++;
9,386,160✔
803
            }
804
         }
805
      }
806
   } while (pruned > 0);
105,365✔
807

808
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
265,564✔
809
      block_t *b = &(active_unit->blocks.items[i]);
191,315✔
810
      op_t *dst = &(b->ops.items[0]);
191,315✔
811
      size_t copied = 0;
191,315✔
812
      for (int j = 0; j < b->ops.count; j++) {
2,883,128✔
813
         const op_t *src = &(b->ops.items[j]);
2,691,813✔
814
         if (src->kind != (vcode_op_t)-1) {
2,691,813✔
815
            if (src != dst) {
2,577,654✔
816
               assert(dst < src);
869,538✔
817
               *dst = *src;
869,538✔
818
            }
819
            dst++;
2,577,654✔
820
            copied++;
2,577,654✔
821
         }
822
      }
823

824
      assert(copied <= b->ops.count);
191,315✔
825
      b->ops.count = copied;
191,315✔
826
   }
827
}
74,249✔
828

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

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

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

848
int vcode_count_vars(void)
74,226✔
849
{
850
   assert(active_unit != NULL);
74,226✔
851
   return active_unit->vars.count;
74,226✔
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✔
UNCOV
859
         return i;
×
860
   }
861

862
   return VCODE_INVALID_VAR;
863
}
864

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1007
bool vcode_block_finished(void)
2,847,314✔
1008
{
1009
   assert(active_unit != NULL);
2,847,314✔
1010
   assert(active_block != VCODE_INVALID_BLOCK);
2,847,314✔
1011

1012
   const block_t *b = &(active_unit->blocks.items[active_block]);
2,847,314✔
1013
   if (b->ops.count == 0)
2,847,314✔
1014
      return false;
1015
   else {
1016
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
2,591,632✔
1017
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
2,591,632✔
1018
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
2,591,608✔
1019
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
1020
         || kind == VCODE_OP_UNREACHABLE;
5,183,240✔
1021
   }
1022
}
1023

1024
const char *vcode_op_string(vcode_op_t op)
174,644✔
1025
{
1026
   static const char *strs[] = {
174,644✔
1027
      "cmp", "fcall", "wait", "const", "assert", "jump", "load", "store",
1028
      "mul", "add", "comment", "const array", "index", "sub", "cast",
1029
      "load indirect", "store indirect", "return", "sched waveform",
1030
      "cond", "report", "div", "neg", "exp", "abs", "mod", "rem", "alloc",
1031
      "select", "or", "wrap", "uarray left", "uarray right", "uarray dir",
1032
      "unwrap", "not", "and", "event", "active", "const record", "record ref",
1033
      "copy", "sched event", "pcall", "resume", "xor", "xnor", "nand", "nor",
1034
      "memset", "case", "file open", "file write",
1035
      "file read", "null", "new", "null check", "deallocate", "all",
1036
      "const real", "last event", "debug out", "cover stmt", "cover branch",
1037
      "cover toggle", "cover expr", "cover state", "uarray len", "undefined",
1038
      "range null", "var upref", "resolved", "last value", "init signal",
1039
      "map signal", "drive signal", "link var", "resolution wrapper",
1040
      "last active", "driving", "driving value", "address of", "closure",
1041
      "protected init", "context upref", "const rep", "protected free",
1042
      "implicit signal", "disconnect", "link package",
1043
      "index check", "debug locus", "length check", "range check", "array ref",
1044
      "range length", "exponent check", "zero check", "map const",
1045
      "resolve signal", "package scope", "pop scope", "alias signal",
1046
      "trap add", "trap sub", "trap mul", "force", "release",
1047
      "unreachable", "package init", "trap neg", "process init", "clear event",
1048
      "trap exp", "enter state", "reflect value", "reflect subtype",
1049
      "function trigger", "add trigger", "transfer signal", "bind foreign",
1050
      "or trigger", "cmp trigger", "instance name",
1051
      "map implicit", "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))
174,644✔
1056
      return "???";
1057
   else
1058
      return strs[op];
174,644✔
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
         case VCODE_OP_MAP_IMPLICIT:
1430
            {
1431
               printf("%s ", vcode_op_string(op->kind));
1432
               vcode_dump_reg(op->args.items[0]);
1433
               printf(" to ");
1434
               vcode_dump_reg(op->args.items[1]);
1435
               printf(" count ");
1436
               vcode_dump_reg(op->args.items[2]);
1437
            }
1438
            break;
1439

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

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

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

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

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

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

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

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

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

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

1568
         case VCODE_OP_PROCESS_INIT:
1569
            {
1570
               printf("%s ", vcode_op_string(op->kind));
1571
               vcode_dump_reg(op->args.items[0]);
1572
               printf(" locus ");
1573
               vcode_dump_reg(op->args.items[1]);
1574
            }
1575
            break;
1576

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2420
         case VCODE_OP_INSTANCE_NAME:
2421
         case VCODE_OP_BIND_EXTERNAL:
2422
            {
2423
               col += vcode_dump_reg(op->result);
2424
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
2425
               col += vcode_dump_reg(op->args.items[0]);
2426
               col += nvc_printf(" scope $magenta$%s$$ ", istr(op->ident));
2427
               for (int i = 1; i < op->args.count; i++) {
2428
                  if (i > 1) col += printf(", ");
2429
                  col += vcode_dump_reg(op->args.items[i]);
2430
               }
2431
               vcode_dump_result_type(col, op);
2432
            }
2433
            break;
2434

2435
         case VCODE_OP_GET_COUNTERS:
2436
            {
2437
               col += vcode_dump_reg(op->result);
2438
               col += nvc_printf(":= %s $magenta$%s$$",
2439
                                 vcode_op_string(op->kind), istr(op->ident));
2440
               vcode_dump_result_type(col, op);
2441
            }
2442
            break;
2443
         }
2444

2445
         if (j == mark_op && i == old_block)
2446
            nvc_printf("\t $red$<----$$");
2447

2448
         nvc_printf("$$\n");
2449

2450
         if (callback != NULL)
2451
            (*callback)(j, arg);
2452
      }
2453

2454
      if (b->ops.count == 0)
2455
         nvc_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2456
   }
2457

2458
   printf("\n");
2459
   fflush(stdout);
2460

2461
   active_block = old_block;
2462
}
2463
LCOV_EXCL_STOP
2464

2465
static inline bool vtype_eq_internal(const vtype_t *at, const vtype_t *bt)
21,579,846✔
2466
{
2467
   if (at->kind != bt->kind)
21,579,846✔
2468
      return false;
2469

2470
   switch (at->kind) {
5,649,862✔
2471
   case VCODE_TYPE_INT:
3,754,909✔
2472
      return (at->low == bt->low) && (at->high == bt->high);
5,372,637✔
2473
   case VCODE_TYPE_REAL:
75,797✔
2474
      return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
75,858✔
2475
   case VCODE_TYPE_CARRAY:
161,383✔
2476
      return at->size == bt->size && vtype_eq(at->elem, bt->elem);
172,944✔
2477
   case VCODE_TYPE_UARRAY:
120,366✔
2478
      return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
149,889✔
2479
   case VCODE_TYPE_POINTER:
708,928✔
2480
   case VCODE_TYPE_ACCESS:
2481
      return vtype_eq(at->pointed, bt->pointed);
708,928✔
2482
   case VCODE_TYPE_OFFSET:
2483
   case VCODE_TYPE_OPAQUE:
2484
   case VCODE_TYPE_DEBUG_LOCUS:
2485
   case VCODE_TYPE_TRIGGER:
2486
      return true;
2487
   case VCODE_TYPE_RESOLUTION:
125,153✔
2488
   case VCODE_TYPE_CLOSURE:
2489
   case VCODE_TYPE_SIGNAL:
2490
   case VCODE_TYPE_FILE:
2491
      return vtype_eq(at->base, bt->base);
125,153✔
2492
   case VCODE_TYPE_RECORD:
89,975✔
2493
   case VCODE_TYPE_CONTEXT:
2494
      return at->name == bt->name;
89,975✔
UNCOV
2495
   default:
×
2496
      should_not_reach_here();
2497
   }
2498
}
2499

2500
bool vtype_eq(vcode_type_t a, vcode_type_t b)
7,347,664✔
2501
{
2502
   assert(active_unit != NULL);
7,347,664✔
2503

2504
   if (a == b)
7,347,664✔
2505
      return true;
2506
   else if (MASK_CONTEXT(a) == MASK_CONTEXT(b))
1,450,882✔
2507
      return false;   // Guaranteed by vtype_new
2508
   else {
2509
      const vtype_t *at = vcode_type_data(a);
174,119✔
2510
      const vtype_t *bt = vcode_type_data(b);
174,119✔
2511

2512
      return vtype_eq_internal(at, bt);
174,119✔
2513
   }
2514
}
2515

UNCOV
2516
void vcode_dump(void)
×
2517
{
UNCOV
2518
   vcode_dump_with_mark(-1, NULL, NULL);
×
UNCOV
2519
}
×
2520

2521
static vcode_type_t vtype_new(vtype_t *new)
3,707,998✔
2522
{
2523
   const int index = active_unit->types.count - 1;
3,707,998✔
2524

2525
   for (int i = 0; i < index; i++) {
21,890,962✔
2526
      const vtype_t *cmp = vtype_array_nth_ptr(&(active_unit->types), i);
21,405,727✔
2527
      if (vtype_eq_internal(new, cmp)) {
21,405,727✔
2528
         active_unit->types.count--;
3,222,763✔
2529
         return MAKE_HANDLE(active_unit->depth, i);
3,222,763✔
2530
      }
2531
   }
2532

2533
   return MAKE_HANDLE(active_unit->depth, index);
485,235✔
2534
}
2535

2536
vcode_type_t vtype_int(int64_t low, int64_t high)
2,228,855✔
2537
{
2538
   assert(active_unit != NULL);
2,228,855✔
2539

2540
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
2,228,855✔
2541
   n->kind = VCODE_TYPE_INT;
2,228,855✔
2542
   n->low  = low;
2,228,855✔
2543
   n->high = high;
2,228,855✔
2544

2545
   switch (bits_for_range(low, high)) {
2,228,855✔
2546
   case 64:
79,697✔
2547
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
79,697✔
2548
      break;
79,697✔
2549
   case 32:
506,436✔
2550
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
506,436✔
2551
      break;
506,436✔
2552
   case 16:
243✔
2553
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
243✔
2554
      break;
243✔
2555
   case 8:
1,022,566✔
2556
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
1,022,566✔
2557
      break;
1,022,566✔
2558
   case 1:
619,913✔
2559
      n->repr = VCODE_REPR_U1;
619,913✔
2560
      break;
619,913✔
UNCOV
2561
   case 0:
×
UNCOV
2562
      n->repr = VCODE_REPR_I64;    // Null range
×
UNCOV
2563
      break;
×
UNCOV
2564
   default:
×
2565
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2566
   }
2567

2568
   return vtype_new(n);
2,228,855✔
2569
}
2570

2571
vcode_type_t vtype_bool(void)
477,087✔
2572
{
2573
   return vtype_int(0, 1);
477,087✔
2574
}
2575

2576
vcode_type_t vtype_carray(int size, vcode_type_t elem)
88,359✔
2577
{
2578
   assert(active_unit != NULL);
88,359✔
2579

2580
   const vtype_kind_t ekind = vtype_kind(elem);
88,359✔
2581
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
88,359✔
2582
                "array types may not be nested");
2583

2584
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
88,359✔
2585
   memset(n, '\0', sizeof(vtype_t));
88,359✔
2586
   n->kind   = VCODE_TYPE_CARRAY;
88,359✔
2587
   n->elem   = elem;
88,359✔
2588
   n->size   = MAX(size, 0);
88,359✔
2589

2590
   return vtype_new(n);
88,359✔
2591
}
2592

2593
vcode_type_t vtype_find_named_record(ident_t name)
44,537✔
2594
{
2595
   assert(active_unit != NULL);
44,537✔
2596

2597
   for (int i = 0; i < active_unit->types.count; i++) {
419,002✔
2598
      vtype_t *other = &(active_unit->types.items[i]);
401,318✔
2599
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
401,318✔
2600
         return MAKE_HANDLE(active_unit->depth, i);
26,853✔
2601
   }
2602

2603
   return VCODE_INVALID_TYPE;
2604
}
2605

2606
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
17,684✔
2607
                                int nfields)
2608
{
2609
   assert(active_unit != NULL);
17,684✔
2610

2611
   vtype_t *data = NULL;
17,684✔
2612
   vcode_type_t handle = vtype_find_named_record(name);
17,684✔
2613
   if (handle == VCODE_INVALID_TYPE) {
17,684✔
2614
      data = vtype_array_alloc(&(active_unit->types));
8,842✔
2615
      memset(data, '\0', sizeof(vtype_t));
8,842✔
2616
      data->kind = VCODE_TYPE_RECORD;
8,842✔
2617
      data->name = name;
8,842✔
2618

2619
      handle = vtype_new(data);
8,842✔
2620
   }
2621
   else {
2622
      data = vcode_type_data(handle);
8,842✔
2623
      VCODE_ASSERT(data->fields.count == 0,
8,842✔
2624
                    "record type %s already defined", istr(name));
2625
   }
2626

2627
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
17,684✔
2628
   for (int i = 0; i < nfields; i++)
47,127✔
2629
      vcode_type_array_add(&(data->fields), field_types[i]);
29,443✔
2630

2631
   return handle;
17,684✔
2632
}
2633

2634
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem)
116,859✔
2635
{
2636
   assert(active_unit != NULL);
116,859✔
2637

2638
   const vtype_kind_t ekind = vtype_kind(elem);
116,859✔
2639
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
116,859✔
2640
                "array types may not be nested");
2641

2642
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
116,859✔
2643

2644
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
116,859✔
2645
   memset(n, '\0', sizeof(vtype_t));
116,859✔
2646
   n->kind = VCODE_TYPE_UARRAY;
116,859✔
2647
   n->elem = elem;
116,859✔
2648
   n->dims = ndim;
116,859✔
2649

2650
   return vtype_new(n);
116,859✔
2651
}
2652

2653
vcode_type_t vtype_pointer(vcode_type_t to)
299,630✔
2654
{
2655
   assert(active_unit != NULL);
299,630✔
2656

2657
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
299,630✔
2658
   n->kind    = VCODE_TYPE_POINTER;
299,630✔
2659
   n->pointed = to;
299,630✔
2660

2661
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
299,630✔
2662
                "cannot get pointer to carray type");
2663

2664
   return vtype_new(n);
299,630✔
2665
}
2666

2667
vcode_type_t vtype_access(vcode_type_t to)
10,504✔
2668
{
2669
   assert(active_unit != NULL);
10,504✔
2670

2671
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
10,504✔
2672
   n->kind    = VCODE_TYPE_ACCESS;
10,504✔
2673
   n->pointed = to;
10,504✔
2674

2675
   return vtype_new(n);
10,504✔
2676
}
2677

2678
vcode_type_t vtype_signal(vcode_type_t base)
66,981✔
2679
{
2680
   assert(active_unit != NULL);
66,981✔
2681

2682
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
66,981✔
2683
   n->kind = VCODE_TYPE_SIGNAL;
66,981✔
2684
   n->base = base;
66,981✔
2685

2686
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
66,981✔
2687

2688
   return vtype_new(n);
66,981✔
2689
}
2690

2691
vcode_type_t vtype_resolution(vcode_type_t base)
15,918✔
2692
{
2693
   assert(active_unit != NULL);
15,918✔
2694

2695
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
15,918✔
2696
   n->kind = VCODE_TYPE_RESOLUTION;
15,918✔
2697
   n->base = base;
15,918✔
2698

2699
   return vtype_new(n);
15,918✔
2700
}
2701

2702
vcode_type_t vtype_closure(vcode_type_t result)
11,243✔
2703
{
2704
   assert(active_unit != NULL);
11,243✔
2705

2706
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
11,243✔
2707
   n->kind = VCODE_TYPE_CLOSURE;
11,243✔
2708
   n->base = result;
11,243✔
2709

2710
   return vtype_new(n);
11,243✔
2711
}
2712

2713
vcode_type_t vtype_context(ident_t name)
81,074✔
2714
{
2715
   assert(active_unit != NULL);
81,074✔
2716
   assert(name != NULL);
81,074✔
2717

2718
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
81,074✔
2719
   n->kind = VCODE_TYPE_CONTEXT;
81,074✔
2720
   n->name = name;
81,074✔
2721

2722
   return vtype_new(n);
81,074✔
2723
}
2724

2725
vcode_type_t vtype_file(vcode_type_t base)
2,546✔
2726
{
2727
   assert(active_unit != NULL);
2,546✔
2728

2729
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
2,546✔
2730
   n->kind = VCODE_TYPE_FILE;
2,546✔
2731
   n->base = base;
2,546✔
2732

2733
   return vtype_new(n);
2,546✔
2734
}
2735

2736
vcode_type_t vtype_offset(void)
454,201✔
2737
{
2738
   assert(active_unit != NULL);
454,201✔
2739

2740
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
454,201✔
2741
   n->kind = VCODE_TYPE_OFFSET;
454,201✔
2742
   n->low  = INT64_MIN;
454,201✔
2743
   n->high = INT64_MAX;
454,201✔
2744
   n->repr = VCODE_REPR_I64;
454,201✔
2745

2746
   return vtype_new(n);
454,201✔
2747
}
2748

2749
vcode_type_t vtype_time(void)
19,367✔
2750
{
2751
   return vtype_int(INT64_MIN, INT64_MAX);
19,367✔
2752
}
2753

2754
vcode_type_t vtype_char(void)
24,185✔
2755
{
2756
   return vtype_int(0, 255);
24,185✔
2757
}
2758

2759
vcode_type_t vtype_opaque(void)
4,442✔
2760
{
2761
   assert(active_unit != NULL);
4,442✔
2762

2763
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
4,442✔
2764
   n->kind = VCODE_TYPE_OPAQUE;
4,442✔
2765

2766
   return vtype_new(n);
4,442✔
2767
}
2768

2769
vcode_type_t vtype_debug_locus(void)
233,057✔
2770
{
2771
   assert(active_unit != NULL);
233,057✔
2772

2773
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
233,057✔
2774
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
233,057✔
2775

2776
   return vtype_new(n);
233,057✔
2777
}
2778

2779
vcode_type_t vtype_trigger(void)
679✔
2780
{
2781
   assert(active_unit != NULL);
679✔
2782

2783
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
679✔
2784
   n->kind = VCODE_TYPE_TRIGGER;
679✔
2785

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

2789
vcode_type_t vtype_real(double low, double high)
84,808✔
2790
{
2791
   assert(active_unit != NULL);
84,808✔
2792

2793
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
84,808✔
2794
   n->kind  = VCODE_TYPE_REAL;
84,808✔
2795
   n->rlow  = low;
84,808✔
2796
   n->rhigh = high;
84,808✔
2797

2798
   return vtype_new(n);
84,808✔
2799
}
2800

2801
vtype_kind_t vtype_kind(vcode_type_t type)
5,797,144✔
2802
{
2803
   vtype_t *vt = vcode_type_data(type);
5,797,144✔
2804
   return vt->kind;
5,797,144✔
2805
}
2806

2807
vtype_repr_t vtype_repr(vcode_type_t type)
57,709✔
2808
{
2809
   vtype_t *vt = vcode_type_data(type);
57,709✔
2810
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
57,709✔
2811
   return vt->repr;
57,709✔
2812
}
2813

2814
vcode_type_t vtype_elem(vcode_type_t type)
198,887✔
2815
{
2816
   vtype_t *vt = vcode_type_data(type);
198,887✔
2817
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
198,887✔
2818
   return vt->elem;
198,887✔
2819
}
2820

2821
vcode_type_t vtype_base(vcode_type_t type)
89,162✔
2822
{
2823
   vtype_t *vt = vcode_type_data(type);
89,162✔
2824
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
89,162✔
2825
          || vt->kind == VCODE_TYPE_RESOLUTION
2826
          || vt->kind == VCODE_TYPE_CLOSURE);
2827
   return vt->base;
89,162✔
2828
}
2829

2830
unsigned vtype_dims(vcode_type_t type)
61,742✔
2831
{
2832
   vtype_t *vt = vcode_type_data(type);
61,742✔
2833
   assert(vt->kind == VCODE_TYPE_UARRAY);
61,742✔
2834
   return vt->dims;
61,742✔
2835
}
2836

2837
unsigned vtype_size(vcode_type_t type)
80,259✔
2838
{
2839
   vtype_t *vt = vcode_type_data(type);
80,259✔
2840
   assert(vt->kind == VCODE_TYPE_CARRAY);
80,259✔
2841
   return vt->size;
80,259✔
2842
}
2843

2844
int vtype_fields(vcode_type_t type)
12,169✔
2845
{
2846
   vtype_t *vt = vcode_type_data(type);
12,169✔
2847
   assert(vt->kind == VCODE_TYPE_RECORD);
12,169✔
2848
   return vt->fields.count;
12,169✔
2849
}
2850

2851
vcode_type_t vtype_field(vcode_type_t type, int field)
48,072✔
2852
{
2853
   vtype_t *vt = vcode_type_data(type);
48,072✔
2854
   assert(vt->kind == VCODE_TYPE_RECORD);
48,072✔
2855
   return vcode_type_array_nth(&(vt->fields), field);
48,072✔
2856
}
2857

2858
ident_t vtype_name(vcode_type_t type)
26,885✔
2859
{
2860
   vtype_t *vt = vcode_type_data(type);
26,885✔
2861
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
26,885✔
2862
   return vt->name;
26,885✔
2863
}
2864

2865
vcode_type_t vtype_pointed(vcode_type_t type)
486,824✔
2866
{
2867
   vtype_t *vt = vcode_type_data(type);
486,824✔
2868
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
486,824✔
2869
   return vt->pointed;
486,824✔
2870
}
2871

2872
int64_t vtype_low(vcode_type_t type)
118,841✔
2873
{
2874
   vtype_t *vt = vcode_type_data(type);
118,841✔
2875
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
118,841✔
2876
   return vt->low;
118,841✔
2877
}
2878

2879
int64_t vtype_high(vcode_type_t type)
119,621✔
2880
{
2881
   vtype_t *vt = vcode_type_data(type);
119,621✔
2882
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
119,621✔
2883
   return vt->high;
119,621✔
2884
}
2885

2886
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
2,526✔
2887
{
2888
   return vtype_kind(type) == VCODE_TYPE_POINTER
2,526✔
2889
      && vtype_kind(vtype_pointed(type)) == to;
2,526✔
2890
}
2891

2892
bool vtype_is_scalar(vcode_type_t type)
614,934✔
2893
{
2894
   const vtype_kind_t kind = vtype_kind(type);
614,934✔
2895
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
614,934✔
2896
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
248,501✔
2897
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2898
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2899
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER
2900
      || kind == VCODE_TYPE_RESOLUTION;
614,934✔
2901
}
2902

2903
bool vtype_is_numeric(vcode_type_t type)
24,934✔
2904
{
2905
   const vtype_kind_t kind = vtype_kind(type);
24,934✔
2906
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
24,934✔
2907
      || kind == VCODE_TYPE_REAL;
24,934✔
2908
}
2909

2910
bool vtype_is_integral(vcode_type_t type)
1,224✔
2911
{
2912
   const vtype_kind_t kind = vtype_kind(type);
1,224✔
2913
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET;
1,224✔
2914
}
2915

2916
bool vtype_is_composite(vcode_type_t type)
49,607✔
2917
{
2918
   const vtype_kind_t kind = vtype_kind(type);
49,607✔
2919
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
49,607✔
2920
}
2921

2922
bool vtype_is_signal(vcode_type_t type)
212,730✔
2923
{
2924
   vtype_t *vt = vcode_type_data(type);
378,992✔
2925
   switch (vt->kind) {
378,992✔
2926
   case VCODE_TYPE_SIGNAL:
2927
      return true;
2928
   case VCODE_TYPE_POINTER:
98,573✔
2929
      return vtype_is_signal(vt->pointed);
98,573✔
2930
   case VCODE_TYPE_RECORD:
2931
      for (int i = 0; i < vt->fields.count; i++) {
48,658✔
2932
         if (vtype_is_signal(vt->fields.items[i]))
38,309✔
2933
            return true;
2934
      }
2935
      return false;
2936
   case VCODE_TYPE_UARRAY:
67,689✔
2937
   case VCODE_TYPE_CARRAY:
2938
      return vtype_is_signal(vt->elem);
67,689✔
2939
   default:
163,344✔
2940
      return false;
163,344✔
2941
   }
2942
}
2943

UNCOV
2944
int vtype_repr_bits(vtype_repr_t repr)
×
2945
{
UNCOV
2946
   switch (repr) {
×
2947
   case VCODE_REPR_U1: return 1;
2948
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2949
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2950
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2951
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2952
   default: return -1;
2953
   }
2954
}
2955

UNCOV
2956
bool vtype_repr_signed(vtype_repr_t repr)
×
2957
{
UNCOV
2958
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
×
UNCOV
2959
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
×
2960
}
2961

2962
static int64_t vtype_repr_low(vtype_repr_t repr)
18,626✔
2963
{
2964
   switch (repr) {
18,626✔
2965
   case VCODE_REPR_U1:
2966
   case VCODE_REPR_U8:
2967
   case VCODE_REPR_U16:
2968
   case VCODE_REPR_U32:
2969
   case VCODE_REPR_U64: return 0;
2970
   case VCODE_REPR_I8:  return INT8_MIN;
2971
   case VCODE_REPR_I16: return INT16_MIN;
2972
   case VCODE_REPR_I32: return INT32_MIN;
2973
   case VCODE_REPR_I64: return INT64_MIN;
2974
   default:             return 0;
2975
   }
2976
}
2977

2978
static uint64_t vtype_repr_high(vtype_repr_t repr)
18,626✔
2979
{
2980
   switch (repr) {
18,626✔
2981
   case VCODE_REPR_U1:  return 1;
2982
   case VCODE_REPR_U8:  return UINT8_MAX;
2983
   case VCODE_REPR_U16: return UINT16_MAX;
2984
   case VCODE_REPR_U32: return UINT32_MAX;
2985
   case VCODE_REPR_U64: return UINT64_MAX;
2986
   case VCODE_REPR_I8:  return INT8_MAX;
2987
   case VCODE_REPR_I16: return INT16_MAX;
2988
   case VCODE_REPR_I32: return INT32_MAX;
2989
   case VCODE_REPR_I64: return INT64_MAX;
2990
   default:             return 0;
2991
   }
2992
}
2993

2994
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
18,626✔
2995
{
2996
   int64_t clamp_low = vtype_repr_low(repr);
18,626✔
2997
   uint64_t clamp_high = vtype_repr_high(repr);
18,626✔
2998

2999
   if (*low >= clamp_low && *high <= clamp_high)
18,626✔
3000
      return true;
3001
   else {
3002
      *low = MAX(clamp_low, *low);
8,935✔
3003
      *high = MIN(clamp_high, *high);
8,935✔
3004
      return false;
8,935✔
3005
   }
3006
}
3007

3008
static vcode_stamp_t vstamp_new(const vstamp_t *s)
1,099,967✔
3009
{
3010
   assert(active_unit != NULL);
1,099,967✔
3011

3012
   for (int i = 0; i < active_unit->stamps.count; i++) {
10,875,843✔
3013
      vstamp_t *cmp = &(active_unit->stamps.items[i]);
10,389,523✔
3014
      if (cmp->kind == s->kind && memcmp(&cmp->u, &s->u, sizeof(s->u)) == 0)
10,389,523✔
3015
         return MAKE_HANDLE(active_unit->depth, i);
613,647✔
3016
   }
3017

3018
   vstamp_t *new = vstamp_array_alloc(&(active_unit->stamps));
486,320✔
3019
   *new = *s;
486,320✔
3020

3021
   return MAKE_HANDLE(active_unit->depth, active_unit->stamps.count - 1);
486,320✔
3022
}
3023

3024
vcode_stamp_t vstamp_int(int64_t low, int64_t high)
1,044,400✔
3025
{
3026
   const vstamp_t s = {
1,044,400✔
3027
      .kind = VCODE_STAMP_INT,
3028
      .u = { .intg = { .low = low, .high = high } },
3029
   };
3030
   return vstamp_new(&s);
1,044,400✔
3031
}
3032

3033
vcode_stamp_t vstamp_real(double low, double high)
55,567✔
3034
{
3035
   const vstamp_t s = {
55,567✔
3036
      .kind = VCODE_STAMP_REAL,
3037
      .u = { .real = { .low = low, .high = high } },
3038
   };
3039
   return vstamp_new(&s);
55,567✔
3040
}
3041

3042
vcode_stamp_t vstamp_char(void)
8,549✔
3043
{
3044
   return vstamp_int(0, 255);
8,549✔
3045
}
3046

3047
int vcode_count_params(void)
27,534✔
3048
{
3049
   assert(active_unit != NULL);
27,534✔
3050
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
27,534✔
3051
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3052
          || active_unit->kind == VCODE_UNIT_PROPERTY
3053
          || active_unit->kind == VCODE_UNIT_PROTECTED
3054
          || active_unit->kind == VCODE_UNIT_PROCESS);
3055

3056
   return active_unit->params.count;
27,534✔
3057
}
3058

3059
vcode_type_t vcode_param_type(int param)
40,748✔
3060
{
3061
   assert(active_unit != NULL);
40,748✔
3062
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
40,748✔
3063
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3064
          || active_unit->kind == VCODE_UNIT_PROPERTY
3065
          || active_unit->kind == VCODE_UNIT_PROTECTED
3066
          || active_unit->kind == VCODE_UNIT_PROCESS);
3067
   assert(param < active_unit->params.count);
40,748✔
3068

3069
   return active_unit->params.items[param].type;
40,748✔
3070
}
3071

3072
ident_t vcode_param_name(int param)
40,748✔
3073
{
3074
   assert(active_unit != NULL);
40,748✔
3075
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
40,748✔
3076
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3077
          || active_unit->kind == VCODE_UNIT_PROPERTY
3078
          || active_unit->kind == VCODE_UNIT_PROTECTED
3079
          || active_unit->kind == VCODE_UNIT_PROCESS);
3080
   assert(param < active_unit->params.count);
40,748✔
3081

3082
   return active_unit->params.items[param].name;
40,748✔
3083
}
3084

3085
vcode_reg_t vcode_param_reg(int param)
40,748✔
3086
{
3087
   assert(active_unit != NULL);
40,748✔
3088
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
40,748✔
3089
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3090
          || active_unit->kind == VCODE_UNIT_PROPERTY
3091
          || active_unit->kind == VCODE_UNIT_PROTECTED
3092
          || active_unit->kind == VCODE_UNIT_PROCESS);
3093
   assert(param < active_unit->params.count);
40,748✔
3094

3095
   return active_unit->params.items[param].reg;
40,748✔
3096
}
3097

3098
vcode_block_t emit_block(void)
191,315✔
3099
{
3100
   assert(active_unit != NULL);
191,315✔
3101

3102
   vcode_block_t bnum = active_unit->blocks.count;
191,315✔
3103

3104
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
191,315✔
3105
   memset(bptr, '\0', sizeof(block_t));
191,315✔
3106

3107
   if (active_block != VCODE_INVALID_BLOCK)
191,315✔
3108
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
117,066✔
3109
   else
3110
      bptr->last_loc = LOC_INVALID;
74,249✔
3111

3112
   return bnum;
191,315✔
3113
}
3114

3115
void vcode_select_unit(vcode_unit_t unit)
254,786✔
3116
{
3117
   active_unit  = unit;
254,786✔
3118
   active_block = VCODE_INVALID_BLOCK;
254,786✔
3119
}
254,786✔
3120

3121
void vcode_select_block(vcode_block_t block)
414,827✔
3122
{
3123
   assert(active_unit != NULL);
414,827✔
3124
   active_block = block;
414,827✔
3125
}
414,827✔
3126

3127
vcode_block_t vcode_active_block(void)
987✔
3128
{
3129
   assert(active_unit != NULL);
987✔
3130
   assert(active_block != -1);
987✔
3131
   return active_block;
987✔
3132
}
3133

3134
const loc_t *vcode_last_loc(void)
1,929,968✔
3135
{
3136
   return &(vcode_block_data()->last_loc);
1,929,968✔
3137
}
3138

3139
vcode_unit_t vcode_active_unit(void)
912✔
3140
{
3141
   assert(active_unit != NULL);
912✔
3142
   return active_unit;
912✔
3143
}
3144

3145
ident_t vcode_unit_name(vcode_unit_t vu)
214,018✔
3146
{
3147
   assert(vu != NULL);
214,018✔
3148
   return vu->name;
214,018✔
3149
}
3150

3151
bool vcode_unit_has_undefined(vcode_unit_t vu)
14,253✔
3152
{
3153
   assert(vu != NULL);
14,253✔
3154
   return !!(vu->flags & UNIT_UNDEFINED);
14,253✔
3155
}
3156

UNCOV
3157
int vcode_unit_depth(vcode_unit_t vu)
×
3158
{
UNCOV
3159
   assert(vu != NULL);
×
UNCOV
3160
   return vu->depth;
×
3161
}
3162

3163
void vcode_set_result(vcode_type_t type)
26,740✔
3164
{
3165
   assert(active_unit != NULL);
26,740✔
3166
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
26,740✔
3167
          || active_unit->kind == VCODE_UNIT_THUNK);
3168

3169
   active_unit->result = type;
26,740✔
3170
}
26,740✔
3171

3172
vcode_type_t vcode_unit_result(vcode_unit_t vu)
29,776✔
3173
{
3174
   assert(vu != NULL);
29,776✔
3175
   assert(vu->kind == VCODE_UNIT_FUNCTION || vu->kind == VCODE_UNIT_THUNK);
29,776✔
3176
   return vu->result;
29,776✔
3177
}
3178

3179
vunit_kind_t vcode_unit_kind(vcode_unit_t vu)
188,014✔
3180
{
3181
   assert(vu != NULL);
188,014✔
3182
   return vu->kind;
188,014✔
3183
}
3184

3185
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
81,083✔
3186
{
3187
   assert(vu != NULL);
81,083✔
3188
   return vu->context;
81,083✔
3189
}
3190

3191
object_t *vcode_unit_object(vcode_unit_t vu)
110,767✔
3192
{
3193
   assert(vu != NULL);
110,767✔
3194
   return vu->object;
110,767✔
3195
}
3196

3197
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
88,518✔
3198
{
3199
   int hops = 0;
88,518✔
3200
   for (; (unit = unit->context); hops++)
215,201✔
3201
      ;
3202
   return hops;
88,518✔
3203
}
3204

3205
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
38,343✔
3206
{
3207
   assert(context->kind != VCODE_UNIT_THUNK);
38,343✔
3208

3209
   child->next = NULL;
38,343✔
3210
   if (context->children == NULL)
38,343✔
3211
      context->children = child;
18,014✔
3212
   else {
3213
      vcode_unit_t it;
3214
      for (it = context->children; it->next != NULL; it = it->next)
91,544✔
3215
         ;
3216
      it->next = child;
20,329✔
3217
   }
3218
}
38,343✔
3219

3220
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
15,538✔
3221
{
3222
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
15,538✔
3223
   vu->kind     = VCODE_UNIT_FUNCTION;
15,538✔
3224
   vu->name     = name;
15,538✔
3225
   vu->context  = context;
15,538✔
3226
   vu->result   = VCODE_INVALID_TYPE;
15,538✔
3227
   vu->depth    = vcode_unit_calc_depth(vu);
15,538✔
3228
   vu->object   = obj;
15,538✔
3229

3230
   vcode_add_child(context, vu);
15,538✔
3231

3232
   vcode_select_unit(vu);
15,538✔
3233
   vcode_select_block(emit_block());
15,538✔
3234
   emit_debug_info(&(obj->loc));
15,538✔
3235

3236
   return vu;
15,538✔
3237
}
3238

3239
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
281✔
3240
{
3241
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
281✔
3242
   vu->kind     = VCODE_UNIT_PROCEDURE;
281✔
3243
   vu->name     = name;
281✔
3244
   vu->context  = context;
281✔
3245
   vu->result   = VCODE_INVALID_TYPE;
281✔
3246
   vu->depth    = vcode_unit_calc_depth(vu);
281✔
3247
   vu->object   = obj;
281✔
3248

3249
   vcode_add_child(context, vu);
281✔
3250

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

3255
   return vu;
281✔
3256
}
3257

3258
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
10,369✔
3259
{
3260
   assert(context->kind == VCODE_UNIT_INSTANCE);
10,369✔
3261

3262
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
10,369✔
3263
   vu->kind     = VCODE_UNIT_PROCESS;
10,369✔
3264
   vu->name     = name;
10,369✔
3265
   vu->context  = context;
10,369✔
3266
   vu->depth    = vcode_unit_calc_depth(vu);
10,369✔
3267
   vu->result   = VCODE_INVALID_TYPE;
10,369✔
3268
   vu->object   = obj;
10,369✔
3269

3270
   vcode_add_child(context, vu);
10,369✔
3271

3272
   vcode_select_unit(vu);
10,369✔
3273
   vcode_select_block(emit_block());
10,369✔
3274
   emit_debug_info(&(obj->loc));
10,369✔
3275

3276
   return vu;
10,369✔
3277
}
3278

3279
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
16,673✔
3280
{
3281
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
16,673✔
3282

3283
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
16,673✔
3284
   vu->kind     = VCODE_UNIT_INSTANCE;
16,673✔
3285
   vu->name     = name;
16,673✔
3286
   vu->context  = context;
16,673✔
3287
   vu->depth    = vcode_unit_calc_depth(vu);
16,673✔
3288
   vu->result   = VCODE_INVALID_TYPE;
16,673✔
3289
   vu->object   = obj;
16,673✔
3290

3291
   if (context != NULL)
16,673✔
3292
      vcode_add_child(context, vu);
10,130✔
3293

3294
   vcode_select_unit(vu);
16,673✔
3295
   vcode_select_block(emit_block());
16,673✔
3296
   emit_debug_info(&(obj->loc));
16,673✔
3297

3298
   return vu;
16,673✔
3299
}
3300

3301
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
15,773✔
3302
{
3303
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
15,773✔
3304
   vu->kind     = VCODE_UNIT_PACKAGE;
15,773✔
3305
   vu->name     = name;
15,773✔
3306
   vu->context  = context;
15,773✔
3307
   vu->depth    = vcode_unit_calc_depth(vu);
15,773✔
3308
   vu->result   = VCODE_INVALID_TYPE;
15,773✔
3309
   vu->object   = obj;
15,773✔
3310

3311
   if (context != NULL)
15,773✔
3312
      vcode_add_child(context, vu);
309✔
3313

3314
   vcode_select_unit(vu);
15,773✔
3315
   vcode_select_block(emit_block());
15,773✔
3316
   emit_debug_info(&(obj->loc));
15,773✔
3317

3318
   return vu;
15,773✔
3319
}
3320

3321
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
1,022✔
3322
{
3323
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
1,022✔
3324
   vu->kind     = VCODE_UNIT_PROTECTED;
1,022✔
3325
   vu->name     = name;
1,022✔
3326
   vu->context  = context;
1,022✔
3327
   vu->depth    = vcode_unit_calc_depth(vu);
1,022✔
3328
   vu->result   = VCODE_INVALID_TYPE;
1,022✔
3329
   vu->object   = obj;
1,022✔
3330

3331
   if (context != NULL)
1,022✔
3332
      vcode_add_child(context, vu);
1,022✔
3333

3334
   vcode_select_unit(vu);
1,022✔
3335
   vcode_select_block(emit_block());
1,022✔
3336
   emit_debug_info(&(obj->loc));
1,022✔
3337

3338
   return vu;
1,022✔
3339
}
3340

3341
vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context)
324✔
3342
{
3343
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
324✔
3344
   vu->kind     = VCODE_UNIT_PROPERTY;
324✔
3345
   vu->name     = name;
324✔
3346
   vu->context  = context;
324✔
3347
   vu->depth    = vcode_unit_calc_depth(vu);
324✔
3348
   vu->result   = VCODE_INVALID_TYPE;
324✔
3349
   vu->object   = obj;
324✔
3350

3351
   if (context != NULL)
324✔
3352
      vcode_add_child(context, vu);
324✔
3353

3354
   vcode_select_unit(vu);
324✔
3355
   vcode_select_block(emit_block());
324✔
3356
   emit_debug_info(&(obj->loc));
324✔
3357

3358
   return vu;
324✔
3359
}
3360

3361
vcode_unit_t emit_thunk(ident_t name, object_t *obj, vcode_unit_t context)
14,269✔
3362
{
3363
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
14,269✔
3364
   vu->kind     = VCODE_UNIT_THUNK;
14,269✔
3365
   vu->name     = name;
14,269✔
3366
   vu->context  = context;
14,269✔
3367
   vu->depth    = vcode_unit_calc_depth(vu);
14,269✔
3368
   vu->result   = VCODE_INVALID_TYPE;
14,269✔
3369
   vu->depth    = vcode_unit_calc_depth(vu);
14,269✔
3370
   vu->object   = obj;
14,269✔
3371

3372
   if (context != NULL)
14,269✔
3373
      vcode_add_child(context, vu);
370✔
3374

3375
   vcode_select_unit(vu);
14,269✔
3376
   vcode_select_block(emit_block());
14,269✔
3377

3378
   return vu;
14,269✔
3379
}
3380

3381
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
19,564✔
3382
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3383
                 vcode_reg_t hint_right)
3384
{
3385
   int64_t value_const;
19,564✔
3386
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
19,564✔
3387
      emit_comment("Always true assertion on r%d", value);
40✔
3388
      return;
40✔
3389
   }
3390

3391
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
19,524✔
3392
   vcode_add_arg(op, value);
19,524✔
3393
   vcode_add_arg(op, severity);
19,524✔
3394
   vcode_add_arg(op, message);
19,524✔
3395
   vcode_add_arg(op, length);
19,524✔
3396
   vcode_add_arg(op, locus);
19,524✔
3397

3398
   if (hint_left != VCODE_INVALID_REG) {
19,524✔
3399
      vcode_add_arg(op, hint_left);
8,111✔
3400
      vcode_add_arg(op, hint_right);
8,111✔
3401

3402
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
8,111✔
3403
                   "left hint must be scalar");
3404
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
8,111✔
3405
                   "right hint must be scalar");
3406
   }
3407

3408
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
19,524✔
3409
                "value parameter to assert is not bool");
3410
   VCODE_ASSERT(message == VCODE_INVALID_REG
19,524✔
3411
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3412
                "message parameter to assert is not a pointer");
3413
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
19,524✔
3414
                "value parameter to assert is not bool");
3415
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
19,524✔
3416
                "locus argument to report must be a debug locus");
3417
}
3418

3419
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,803✔
3420
                 vcode_reg_t locus)
3421
{
3422
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,803✔
3423
   vcode_add_arg(op, severity);
2,803✔
3424
   vcode_add_arg(op, message);
2,803✔
3425
   vcode_add_arg(op, length);
2,803✔
3426
   vcode_add_arg(op, locus);
2,803✔
3427

3428
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,803✔
3429
                "message parameter to report is not a pointer");
3430
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,803✔
3431
                "message parameter to report is not a character pointer");
3432
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,803✔
3433
                "locus argument to report must be a debug locus");
3434
}
2,803✔
3435

3436
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
46,473✔
3437
{
3438
   if (lhs == rhs) {
46,473✔
3439
      if (cmp == VCODE_CMP_EQ)
521✔
3440
         return emit_const(vtype_bool(), 1);
309✔
3441
      else if (cmp == VCODE_CMP_NEQ)
212✔
UNCOV
3442
         return emit_const(vtype_bool(), 0);
×
3443
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
212✔
UNCOV
3444
         return emit_const(vtype_bool(), 1);
×
3445
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
212✔
3446
         return emit_const(vtype_bool(), 0);
212✔
3447
   }
3448

3449
   int64_t lconst, rconst;
45,952✔
3450
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
45,952✔
3451
      switch (cmp) {
433✔
3452
      case VCODE_CMP_EQ:
398✔
3453
         return emit_const(vtype_bool(), lconst == rconst);
398✔
3454
      case VCODE_CMP_NEQ:
4✔
3455
         return emit_const(vtype_bool(), lconst != rconst);
4✔
3456
      case VCODE_CMP_LT:
15✔
3457
         return emit_const(vtype_bool(), lconst < rconst);
15✔
3458
      case VCODE_CMP_GT:
16✔
3459
         return emit_const(vtype_bool(), lconst > rconst);
16✔
UNCOV
3460
      case VCODE_CMP_LEQ:
×
UNCOV
3461
         return emit_const(vtype_bool(), lconst <= rconst);
×
UNCOV
3462
      case VCODE_CMP_GEQ:
×
UNCOV
3463
         return emit_const(vtype_bool(), lconst >= rconst);
×
UNCOV
3464
      default:
×
3465
         fatal_trace("cannot fold comparison %d", cmp);
3466
      }
3467
   }
3468

3469
   // Reuse any previous operation in this block with the same arguments
3470
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
901,147✔
3471
      if (other->args.count == 2 && other->args.items[0] == lhs
32,839✔
3472
          && other->args.items[1] == rhs && other->cmp == cmp)
2,894✔
3473
         return other->result;
256✔
3474
   }
3475

3476
   op_t *op = vcode_add_op(VCODE_OP_CMP);
45,263✔
3477
   vcode_add_arg(op, lhs);
45,263✔
3478
   vcode_add_arg(op, rhs);
45,263✔
3479
   op->cmp    = cmp;
45,263✔
3480
   op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP);
45,263✔
3481

3482
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
45,263✔
3483
                "arguments to cmp are not the same type");
3484

3485
   return op->result;
45,263✔
3486
}
3487

3488
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_stamp_t stamp,
45,223✔
3489
                       const vcode_reg_t *args, int nargs)
3490
{
3491
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
45,223✔
3492
   o->func = func;
45,223✔
3493
   o->type = type;
45,223✔
3494
   for (int i = 0; i < nargs; i++)
159,584✔
3495
      vcode_add_arg(o, args[i]);
114,361✔
3496

3497
   for (int i = 0; i < nargs; i++)
159,584✔
3498
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
114,361✔
3499
                   "invalid argument to function");
3500

3501
   if (type == VCODE_INVALID_TYPE)
45,223✔
3502
      return (o->result = VCODE_INVALID_REG);
7,274✔
3503
   else
3504
      return (o->result = vcode_add_reg(type, stamp));
37,949✔
3505
}
3506

3507
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
1,143✔
3508
                vcode_block_t resume_bb)
3509
{
3510
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
1,143✔
3511
   o->func = func;
1,143✔
3512
   for (int i = 0; i < nargs; i++)
3,825✔
3513
      vcode_add_arg(o, args[i]);
2,682✔
3514

3515
   vcode_block_array_add(&(o->targets), resume_bb);
1,143✔
3516

3517
   for (int i = 0; i < nargs; i++)
3,825✔
3518
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,682✔
3519
                   "invalid argument to procedure");
3520

3521
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
1,143✔
3522
                "first argument to VHDL procedure must be context pointer");
3523
}
1,143✔
3524

3525
vcode_reg_t emit_alloc(vcode_type_t type, vcode_stamp_t stamp,
10,464✔
3526
                       vcode_reg_t count)
3527
{
3528
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
10,464✔
3529
   op->type = type;
10,464✔
3530
   vcode_add_arg(op, count);
10,464✔
3531

3532
   const vtype_kind_t tkind = vtype_kind(type);
10,464✔
3533
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
10,464✔
3534
                "alloca element type cannot be array");
3535
   VCODE_ASSERT(count != VCODE_INVALID_REG,
10,464✔
3536
                "alloca must have valid count argument");
3537

3538
   return (op->result = vcode_add_reg(vtype_pointer(type), stamp));
10,464✔
3539
}
3540

3541
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
2,334,874✔
3542
{
3543
   // Reuse any previous constant in this block with the same type and value
3544
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
55,550,195✔
3545
      if (other->value == value && vtype_eq(type, other->type))
19,149,324✔
3546
         return other->result;
1,693,816✔
3547
   }
3548

3549
   op_t *op = vcode_add_op(VCODE_OP_CONST);
641,058✔
3550
   op->value  = value;
641,058✔
3551
   op->type   = type;
641,058✔
3552
   op->result = vcode_add_reg(type, vstamp_int(value, value));
641,058✔
3553

3554
   vtype_kind_t type_kind = vtype_kind(type);
641,058✔
3555
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
641,058✔
3556
                "constant must have integer or offset type");
3557

3558
   return op->result;
3559
}
3560

3561
vcode_reg_t emit_const_real(vcode_type_t type, double value)
89,071✔
3562
{
3563
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
2,765,221✔
3564
      if (other->real == value && other->type == type)
1,177,859✔
3565
         return other->result;
34,788✔
3566
   }
3567

3568
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
54,283✔
3569
   op->real   = value;
54,283✔
3570
   op->type   = type;
54,283✔
3571
   op->result = vcode_add_reg(op->type, vstamp_real(value, value));
54,283✔
3572

3573
   return op->result;
54,283✔
3574
}
3575

3576
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
56,783✔
3577
{
3578
   vtype_kind_t kind = vtype_kind(type);
56,783✔
3579

3580
   // Reuse any previous operation in this block with the same arguments
3581
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
3,088,697✔
3582
      if (other->args.count != num)
222,599✔
3583
         continue;
131,896✔
3584
      else if (!vtype_eq(vcode_reg_type(other->result), type))
90,703✔
3585
         continue;
3,799✔
3586

3587
      bool match = true;
3588
      for (int i = 0; match && i < num; i++) {
675,491✔
3589
         if (other->args.items[i] != values[i])
588,587✔
3590
            match = false;
77,340✔
3591
      }
3592

3593
      if (match) return other->result;
86,904✔
3594
   }
3595

3596
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
47,219✔
3597
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
47,219✔
3598

3599
   for (int i = 0; i < num; i++)
2,819,438✔
3600
      vcode_add_arg(op, values[i]);
2,772,219✔
3601

3602
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
47,219✔
3603
                "constant array must have constrained array type");
3604
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
47,219✔
3605
                vtype_size(type), num);
3606

3607
#ifdef DEBUG
3608
   vcode_type_t elem = vtype_elem(type);
47,219✔
3609
   for (int i = 0; i < num; i++) {
2,819,438✔
3610
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
2,772,219✔
3611
                   "wrong element type for item %d", i);
3612
      vcode_assert_const(values[i], "array");
2,772,219✔
3613
   }
3614
#endif
3615

3616
   return op->result;
47,219✔
3617
}
3618

3619
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
634✔
3620
{
3621
   // Reuse any previous operation in this block with the same arguments
3622
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
11,837✔
3623
      if (other->args.items[0] == value && other->value == rep)
560✔
3624
         return other->result;
234✔
3625
   }
3626

3627
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
400✔
3628
   op->value = rep;
400✔
3629
   vcode_add_arg(op, value);
400✔
3630

3631
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
400✔
3632
                "constant array must have constrained array type");
3633
   VCODE_ASSERT(rep >= 0, "repeat count must be non-negative");
400✔
3634

3635
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
400✔
3636

3637
   return (op->result = vcode_add_reg(type, vcode_reg_data(value)->stamp));
400✔
3638
}
3639

3640
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
3,600✔
3641
{
3642
   // Reuse any previous constant in this block with the same type and value
3643
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
55,572✔
3644
      if (other->args.count == num && vtype_eq(type, other->type)) {
1,992✔
3645
         bool same_regs = true;
3646
         for (int i = 0; same_regs && i < num; i++)
3,451✔
3647
            same_regs = other->args.items[i] == values[i];
2,001✔
3648

3649
         if (same_regs)
1,450✔
3650
            return other->result;
251✔
3651
      }
3652
   }
3653

3654
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
3,349✔
3655
   op->type   = type;
3,349✔
3656
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
3,349✔
3657

3658
   for (int i = 0; i < num; i++)
11,826✔
3659
      vcode_add_arg(op, values[i]);
8,477✔
3660

3661
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
3,349✔
3662
                "constant record must have record type");
3663

3664
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
3,349✔
3665
                vtype_fields(type), num);
3666

3667
#ifdef DEBUG
3668
   for (int i = 0; i < num; i++) {
11,826✔
3669
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
8,477✔
3670
                   "wrong type for field %d", i);
3671
      vcode_assert_const(values[i], "record");
8,477✔
3672
   }
3673
#endif
3674

3675
   return op->result;
3,349✔
3676
}
3677

3678
vcode_reg_t emit_address_of(vcode_reg_t value)
59,189✔
3679
{
3680
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
3,203,146✔
3681
      if (other->args.items[0] == value)
224,185✔
3682
         return other->result;
9,582✔
3683
   }
3684

3685
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
49,607✔
3686
   vcode_add_arg(op, value);
49,607✔
3687

3688
   vcode_type_t vtype = vcode_reg_type(value);
49,607✔
3689

3690
   VCODE_ASSERT(vtype_is_composite(vtype),
49,607✔
3691
                "address of argument must be record or array");
3692

3693
   if (vtype_kind(vtype) == VCODE_TYPE_CARRAY) {
49,607✔
3694
      vcode_type_t elem = vtype_elem(vtype);
46,957✔
3695
      vcode_stamp_t stamp = vcode_reg_stamp(value);
46,957✔
3696
      return (op->result = vcode_add_reg(vtype_pointer(elem), stamp));
46,957✔
3697
   }
3698
   else {
3699
      vcode_stamp_t stamp = VCODE_INVALID_STAMP;
2,650✔
3700
      return (op->result = vcode_add_reg(vtype_pointer(vtype), stamp));
2,650✔
3701
   }
3702
}
3703

3704
void emit_wait(vcode_block_t target)
17,339✔
3705
{
3706
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
17,339✔
3707
   vcode_add_target(op, target);
17,339✔
3708
}
17,339✔
3709

3710
void emit_jump(vcode_block_t target)
48,426✔
3711
{
3712
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
48,426✔
3713
   vcode_add_target(op, target);
48,426✔
3714

3715
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
48,426✔
3716
}
48,426✔
3717

3718
vcode_var_t emit_var(vcode_type_t type, vcode_stamp_t stamp, ident_t name,
123,006✔
3719
                     vcode_var_flags_t flags)
3720
{
3721
   assert(active_unit != NULL);
123,006✔
3722

3723
   vcode_var_t var = active_unit->vars.count;
123,006✔
3724
   var_t *v = var_array_alloc(&(active_unit->vars));
123,006✔
3725
   memset(v, '\0', sizeof(var_t));
123,006✔
3726
   v->type  = type;
123,006✔
3727
   v->stamp = stamp;
123,006✔
3728
   v->name  = name;
123,006✔
3729
   v->flags = flags;
123,006✔
3730

3731
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
123,006✔
3732

3733
   return var;
123,006✔
3734
}
3735

3736
vcode_reg_t emit_param(vcode_type_t type, vcode_stamp_t stamp, ident_t name)
41,118✔
3737
{
3738
   assert(active_unit != NULL);
41,118✔
3739

3740
   param_t *p = param_array_alloc(&(active_unit->params));
41,118✔
3741
   memset(p, '\0', sizeof(param_t));
41,118✔
3742
   p->type  = type;
41,118✔
3743
   p->stamp = stamp;
41,118✔
3744
   p->name  = name;
41,118✔
3745
   p->reg   = vcode_add_reg(type, stamp);
41,118✔
3746

3747
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
41,118✔
3748

3749
   return p->reg;
41,118✔
3750
}
3751

3752
vcode_reg_t emit_load(vcode_var_t var)
77,841✔
3753
{
3754
   // Try scanning backwards through the block for another load or store to
3755
   // this variable
3756
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
77,841✔
3757
   vcode_reg_t fold = VCODE_INVALID_REG;
77,841✔
3758
   VCODE_FOR_EACH_OP(other) {
1,276,433✔
3759
      switch (state) {
1,217,713✔
3760
      case EAGER:
492,767✔
3761
         if (other->kind == VCODE_OP_LOAD && other->address == var)
492,767✔
3762
            return other->result;
5,091✔
3763
         else if (other->kind == VCODE_OP_STORE && other->address == var)
487,676✔
3764
            return other->args.items[0];
14,030✔
3765
         else if (other->kind == VCODE_OP_FCALL
473,646✔
3766
                  || other->kind == VCODE_OP_PCALL
473,646✔
3767
                  || other->kind == VCODE_OP_FILE_READ
3768
                  || other->kind == VCODE_OP_FILE_OPEN
3769
                  || other->kind == VCODE_OP_STORE_INDIRECT
3770
                  || other->kind == VCODE_OP_DEALLOCATE)
3771
            state = CONSERVATIVE;   // May write to variable
13,415✔
3772
         break;
3773

3774
      case CONSERVATIVE:
682,615✔
3775
         if (other->kind == VCODE_OP_LOAD && other->address == var
682,615✔
3776
             && fold == VCODE_INVALID_REG)
5,913✔
3777
            fold = other->result;
4,714✔
3778
         else if (other->kind == VCODE_OP_STORE && other->address == var
677,901✔
3779
                  && fold == VCODE_INVALID_REG)
3,706✔
3780
            fold = other->args.items[0];
3,490✔
3781
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
674,411✔
3782
            state = UNSAFE;
3783
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
672,528✔
3784
            state = UNSAFE;   // Nested call captures variables
180✔
3785
         break;
3786

3787
      case UNSAFE:
3788
         break;
3789
      }
3790
   }
3791

3792
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
58,720✔
3793
      return fold;
3794

3795
   var_t *v = vcode_var_data(var);
51,045✔
3796

3797
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
51,045✔
3798
   op->address = var;
51,045✔
3799
   op->result  = vcode_add_reg(v->type, v->stamp);
51,045✔
3800

3801
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
51,045✔
3802

3803
   return op->result;
3804
}
3805

3806
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
132,961✔
3807
{
3808
   VCODE_FOR_EACH_OP(other) {
1,608,189✔
3809
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,520,950✔
3810
          && other->args.items[0] == reg) {
224,163✔
3811
         return other->result;
15,286✔
3812
      }
3813
      else if (other->kind == VCODE_OP_FCALL
1,505,664✔
3814
               || other->kind == VCODE_OP_PCALL
1,505,664✔
3815
               || other->kind == VCODE_OP_STORE
3816
               || other->kind == VCODE_OP_STORE_INDIRECT
3817
               || other->kind == VCODE_OP_MEMSET
3818
               || other->kind == VCODE_OP_COPY
3819
               || other->kind == VCODE_OP_FILE_READ)
3820
         break;   // May write to this pointer
3821
   }
3822

3823
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
117,675✔
3824
   vcode_add_arg(op, reg);
117,675✔
3825

3826
   vcode_type_t rtype = vcode_reg_type(reg);
117,675✔
3827

3828
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
117,675✔
3829
                "load indirect with non-pointer argument");
3830

3831
   vcode_type_t deref = vtype_pointed(rtype);
117,675✔
3832
   op->result = vcode_add_reg(deref, vcode_reg_stamp(reg));
117,675✔
3833

3834
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
117,675✔
3835

3836
   return op->result;
3837
}
3838

3839
void emit_store(vcode_reg_t reg, vcode_var_t var)
123,513✔
3840
{
3841
   // Any previous store to this variable in this block is dead
3842
   VCODE_FOR_EACH_OP(other) {
2,658,763✔
3843
      if (other->kind == VCODE_OP_STORE && other->address == var) {
2,555,124✔
3844
         other->kind = VCODE_OP_COMMENT;
384✔
3845
         other->comment =
768✔
3846
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
384✔
3847
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
384✔
3848
      }
3849
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
2,554,740✔
3850
         break;   // Needs to get variable for display
3851
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
2,546,189✔
3852
               && other->address == var)
56,766✔
3853
         break;   // Previous value may be used
3854
   }
3855

3856
   var_t *v = vcode_var_data(var);
123,513✔
3857
   reg_t *r = vcode_reg_data(reg);
123,513✔
3858

3859
   op_t *op = vcode_add_op(VCODE_OP_STORE);
123,513✔
3860
   vcode_add_arg(op, reg);
123,513✔
3861
   op->address = var;
123,513✔
3862

3863
   VCODE_ASSERT(vtype_eq(v->type, r->type),
123,513✔
3864
                "variable and stored value do not have same type");
3865
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
123,513✔
3866
}
123,513✔
3867

3868
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
22,181✔
3869
{
3870
   reg_t *p = vcode_reg_data(ptr);
22,181✔
3871
   reg_t *r = vcode_reg_data(reg);
22,181✔
3872

3873
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
22,181✔
3874
   vcode_add_arg(op, reg);
22,181✔
3875
   vcode_add_arg(op, ptr);
22,181✔
3876

3877
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
22,181✔
3878
                "store indirect target is not a pointer");
3879
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
22,181✔
3880
                "pointer and stored value do not have same type");
3881
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
22,181✔
3882
}
22,181✔
3883

3884
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
90,561✔
3885
                              vcode_reg_t locus)
3886
{
3887
   // Reuse any previous operation in this block with the same arguments
3888
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
2,252,484✔
3889
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
118,030✔
3890
         return other->result;
8,300✔
3891
   }
3892

3893
   op_t *op = vcode_add_op(kind);
82,261✔
3894
   vcode_add_arg(op, lhs);
82,261✔
3895
   vcode_add_arg(op, rhs);
82,261✔
3896
   if (locus != VCODE_INVALID_REG)
82,261✔
3897
      vcode_add_arg(op, locus);
9,720✔
3898

3899
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
82,261✔
3900

3901
   vcode_type_t lhs_type = vcode_reg_type(lhs);
82,261✔
3902
   vcode_type_t rhs_type = vcode_reg_type(rhs);
82,261✔
3903

3904
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
82,261✔
3905
                "arguments to %s are not the same type", vcode_op_string(kind));
3906

3907
   return op->result;
82,261✔
3908
}
3909

3910
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
70,193✔
3911
                               vcode_reg_t locus)
3912
{
3913
   int64_t lconst, rconst;
70,193✔
3914
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
70,193✔
3915
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
70,193✔
3916
   if (l_is_const && r_is_const)
70,193✔
3917
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
34,130✔
3918
   else if (r_is_const && rconst == 1)
36,063✔
3919
      return lhs;
3920
   else if (l_is_const && lconst == 1)
6,743✔
3921
      return rhs;
3922
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
6,039✔
3923
      return emit_const(vcode_reg_type(lhs), 0);
79✔
3924

3925
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
5,960✔
3926

3927
   double rl_low, rl_high, rr_low, rr_high;
5,960✔
3928
   int64_t l_low, l_high, r_low, r_high;
5,960✔
3929

3930
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
5,960✔
3931
       && vcode_reg_bounds(rhs, &r_low, &r_high)) {
5,253✔
3932
      const int64_t ll = smul64(l_low, r_low);
5,253✔
3933
      const int64_t lh = smul64(l_low, r_high);
5,253✔
3934
      const int64_t hl = smul64(l_high, r_low);
5,253✔
3935
      const int64_t hh = smul64(l_high, r_high);
5,253✔
3936

3937
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
5,253✔
3938
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
5,253✔
3939

3940
      if (min > INT64_MIN && max < INT64_MAX) {
5,253✔
3941
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
2,921✔
3942
         if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
2,921✔
3943
            op = VCODE_OP_MUL;   // Cannot overflow
945✔
3944
            locus = VCODE_INVALID_REG;
945✔
3945
         }
3946
      }
3947

3948
      vstamp = vstamp_int(min, max);
5,253✔
3949
   }
3950
   else if (vcode_reg_bounds_real(lhs, &rl_low, &rl_high)
707✔
3951
            && vcode_reg_bounds_real(rhs, &rr_low, &rr_high)) {
707✔
3952
      const double ll = rl_low * rr_low;
707✔
3953
      const double lh = rl_low * rr_high;
707✔
3954
      const double hl = rl_high * rr_low;
707✔
3955
      const double hh = rl_high * rr_high;
707✔
3956

3957
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,641✔
3958
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,761✔
3959

3960
      vstamp = vstamp_real(min, max);
707✔
3961
   }
3962

3963
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
5,960✔
3964

3965
   if (vstamp != VCODE_INVALID_TYPE)
5,960✔
3966
      vcode_reg_data(reg)->stamp = vstamp;
5,960✔
3967

3968
   return reg;
3969
}
3970

3971
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
65,941✔
3972
{
3973
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
65,941✔
3974
}
3975

3976
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
4,252✔
3977
{
3978
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
4,252✔
3979

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

3983
   return result;
4,252✔
3984
}
3985

3986
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
2,406✔
3987
{
3988
   int64_t lconst, rconst;
2,406✔
3989
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
2,406✔
3990
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
2,406✔
3991
   if (l_is_const && r_is_const && rconst != 0)
2,406✔
3992
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
39✔
3993
   else if (r_is_const && rconst == 1)
2,367✔
3994
      return lhs;
3995

3996
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
2,363✔
3997

3998
   int64_t l_low, l_high;
2,363✔
3999
   if (vcode_reg_bounds(lhs, &l_low, &l_high)) {
2,363✔
4000
      if (r_is_const && rconst != 0) {
1,943✔
4001
         reg_t *rr = vcode_reg_data(reg);
1,847✔
4002
         rr->stamp = vstamp_int(l_low / rconst, l_high / rconst);
1,847✔
4003
      }
4004
   }
4005
   else {
4006
      reg_t *rr = vcode_reg_data(reg);
420✔
4007
      rr->stamp = vstamp_real(-INFINITY, INFINITY);
420✔
4008
   }
4009

4010
   return reg;
4011
}
4012

4013
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
191✔
4014
{
4015
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
191✔
4016
}
4017

4018
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
233✔
4019
{
4020
   int64_t rconst;
233✔
4021
   if (vcode_reg_const(rhs, &rconst)) {
233✔
4022
      if (rconst == 0)
113✔
4023
         return emit_const(vcode_reg_type(lhs), 1);
51✔
4024
      else if (rconst == 1)
62✔
4025
         return lhs;
4026
   }
4027

4028
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
181✔
4029

4030
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
181✔
4031
                "trapping exp may only be used with integer types");
4032

4033
   return result;
4034
}
4035

4036
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
256✔
4037
{
4038
   int64_t lconst, rconst;
256✔
4039
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
256✔
4040
       && lconst > 0 && rconst > 0)
19✔
4041
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
4✔
4042

4043
   int64_t l_low, l_high, r_low, r_high;
252✔
4044
   if (vcode_reg_bounds(lhs, &l_low, &l_high) && l_low >= 0
252✔
4045
       && vcode_reg_bounds(rhs, &r_low, &r_high) && r_low >= 0) {
113✔
4046
      // If both arguments are non-negative then rem is equivalent and
4047
      // cheaper to compute
4048
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
108✔
4049

4050
      reg_t *rr = vcode_reg_data(reg);
108✔
4051
      rr->stamp = vstamp_int(0, MAX(0, r_high - 1));
108✔
4052

4053
      return reg;
108✔
4054
   }
4055
   else
4056
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
144✔
4057
}
4058

4059
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
1,166✔
4060
{
4061
   int64_t lconst, rconst;
1,166✔
4062
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
1,166✔
4063
       && lconst > 0 && rconst > 0)
2✔
UNCOV
4064
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
4065

4066
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
1,166✔
4067

4068
   int64_t l_low, l_high, r_low, r_high;
1,166✔
4069
   if (vcode_reg_bounds(lhs, &l_low, &l_high) && l_low >= 0
1,166✔
4070
       && vcode_reg_bounds(rhs, &r_low, &r_high) && r_low >= 0) {
661✔
4071
      reg_t *rr = vcode_reg_data(reg);
656✔
4072
      rr->stamp = vstamp_int(0, r_high - 1);
656✔
4073
   }
4074

4075
   return reg;
4076
}
4077

4078
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
66,646✔
4079
                               vcode_reg_t locus)
4080
{
4081
   int64_t lconst, rconst;
66,646✔
4082
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
66,646✔
4083
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
66,646✔
4084
   if (l_is_const && r_is_const)
66,646✔
4085
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
16,848✔
4086
   else if (r_is_const && rconst == 0)
49,798✔
4087
      return lhs;
4088
   else if (l_is_const && lconst == 0)
49,623✔
4089
      return rhs;
4090

4091
   int64_t l_low, l_high, r_low, r_high;
28,290✔
4092
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
28,290✔
4093
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
28,290✔
4094
       && vcode_reg_bounds(rhs, &r_low, &r_high))  {
27,872✔
4095

4096
      int64_t rbl = sadd64(l_low, r_low);
27,872✔
4097
      int64_t rbh = sadd64(l_high, r_high);
27,872✔
4098

4099
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
27,872✔
4100
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
14,626✔
4101
         if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
14,626✔
4102
            op = VCODE_OP_ADD;   // Cannot overflow
1,909✔
4103
            locus = VCODE_INVALID_REG;
1,909✔
4104
         }
4105
      }
4106

4107
      vstamp = vstamp_int(rbl, rbh);
27,872✔
4108
   }
4109

4110
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
28,290✔
4111

4112
   if (vstamp != VCODE_INVALID_STAMP)
28,290✔
4113
      vcode_reg_data(reg)->stamp = vstamp;
27,872✔
4114

4115
   return reg;
4116
}
4117

4118
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
57,871✔
4119
{
4120
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
57,871✔
4121
}
4122

4123
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
8,775✔
4124
{
4125
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
8,775✔
4126

4127
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
8,775✔
4128
                "trapping add may only be used with integer types");
4129

4130
   return result;
8,775✔
4131
}
4132

4133
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
62,509✔
4134
                               vcode_reg_t locus)
4135
{
4136
   int64_t lconst, rconst;
62,509✔
4137
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
62,509✔
4138
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
62,509✔
4139
   if (l_is_const && r_is_const)
62,509✔
4140
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
11,668✔
4141
   else if (r_is_const && rconst == 0)
50,841✔
4142
      return lhs;
4143
   else if (l_is_const && lconst == 0)
44,193✔
4144
      return emit_neg(rhs);
1,159✔
4145

4146
   int64_t l_low, l_high, r_low, r_high;
43,034✔
4147
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
43,034✔
4148
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
43,034✔
4149
       && vcode_reg_bounds(rhs, &r_low, &r_high))  {
42,658✔
4150

4151
      int64_t rbl = ssub64(l_low, r_high);
42,658✔
4152
      int64_t rbh = ssub64(l_high, r_low);
42,658✔
4153

4154
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
42,658✔
4155
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
40,162✔
4156
         if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
40,162✔
4157
            op = VCODE_OP_SUB;   // Cannot overflow
6,837✔
4158
            locus = VCODE_INVALID_REG;
6,837✔
4159
         }
4160
      }
4161

4162
      vstamp = vstamp_int(rbl, rbh);
42,658✔
4163
   }
4164

4165
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
43,034✔
4166

4167
   if (vstamp != VCODE_INVALID_TYPE)
43,034✔
4168
      vcode_reg_data(reg)->stamp = vstamp;
42,658✔
4169

4170
   return reg;
4171
}
4172

4173
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
53,018✔
4174
{
4175
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
53,018✔
4176
}
4177

4178
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
9,491✔
4179
{
4180
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
9,491✔
4181

4182
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
9,491✔
4183
                "trapping sub may only be used with integer types");
4184

4185
   return result;
9,491✔
4186
}
4187

4188
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
104,958✔
4189
{
4190
   switch (vtype_kind(var->type)) {
104,958✔
4191
   case VCODE_TYPE_CARRAY:
35,132✔
4192
      op->type = vtype_pointer(vtype_elem(var->type));
35,132✔
4193
      op->result = vcode_add_reg(op->type, var->stamp);
35,132✔
4194
      break;
35,132✔
4195

4196
   case VCODE_TYPE_RECORD:
8,470✔
4197
      op->type = vtype_pointer(var->type);
8,470✔
4198
      op->result = vcode_add_reg(op->type, VCODE_INVALID_STAMP);
8,470✔
4199
      break;
8,470✔
4200

4201
   case VCODE_TYPE_INT:
61,356✔
4202
   case VCODE_TYPE_FILE:
4203
   case VCODE_TYPE_ACCESS:
4204
   case VCODE_TYPE_REAL:
4205
   case VCODE_TYPE_UARRAY:
4206
   case VCODE_TYPE_POINTER:
4207
   case VCODE_TYPE_SIGNAL:
4208
   case VCODE_TYPE_CONTEXT:
4209
   case VCODE_TYPE_OFFSET:
4210
   case VCODE_TYPE_TRIGGER:
4211
   case VCODE_TYPE_RESOLUTION:
4212
      op->type = vtype_pointer(var->type);
61,356✔
4213
      op->result = vcode_add_reg(op->type, var->stamp);
61,356✔
4214
      break;
61,356✔
4215

4216
   default:
UNCOV
4217
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4218
                   istr(var->name));
4219
   }
4220
}
104,958✔
4221

4222
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
53,823✔
4223
{
4224
   // Try to find a previous index of this var by this offset
4225
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
2,420,809✔
4226
      if (other->address == var
141,901✔
4227
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
10,341✔
UNCOV
4228
              || (offset != VCODE_INVALID_REG
×
UNCOV
4229
                  && other->args.items[0] == offset)))
×
4230
         return other->result;
10,341✔
4231
   }
4232

4233
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
43,482✔
4234
   op->address = var;
43,482✔
4235

4236
   if (offset != VCODE_INVALID_REG)
43,482✔
UNCOV
4237
      vcode_add_arg(op, offset);
×
4238

4239
   vcode_calculate_var_index_type(op, vcode_var_data(var));
43,482✔
4240

4241
   if (offset != VCODE_INVALID_REG)
43,482✔
UNCOV
4242
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4243
                   "index offset r%d does not have offset type", offset);
4244

4245
   return op->result;
43,482✔
4246
}
4247

4248
vcode_reg_t emit_cast(vcode_type_t type, vcode_stamp_t stamp, vcode_reg_t reg)
346,638✔
4249
{
4250
   if (vtype_eq(vcode_reg_type(reg), type))
346,638✔
4251
      return reg;
346,638✔
4252

4253
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
111,534✔
4254
   vtype_kind_t to   = vtype_kind(type);
111,534✔
4255

4256
   const bool integral =
223,068✔
4257
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
111,534✔
4258
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
111,534✔
4259

4260
   int64_t value;
111,534✔
4261
   if (integral && vcode_reg_const(reg, &value))
111,534✔
4262
      return emit_const(type, value);
17,812✔
4263

4264
   // Try to find a previous cast of this register to this type
4265
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,937,640✔
4266
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
201,298✔
4267
         return other->result;
21,560✔
4268
   }
4269

4270
   op_t *op = vcode_add_op(VCODE_OP_CAST);
72,162✔
4271
   vcode_add_arg(op, reg);
72,162✔
4272
   op->type  = type;
72,162✔
4273

4274
   static const vcode_type_t allowed[][2] = {
72,162✔
4275
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4276
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4277
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4278
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4279
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4280
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4281
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4282
   };
4283

4284
   if (integral) {
72,162✔
4285
      vtype_t *vt = vcode_type_data(type);
70,995✔
4286
      int64_t low = vt->low, high = vt->high;
70,995✔
4287

4288
      vstamp_t *rt = vcode_stamp_data(vcode_reg_data(reg)->stamp);
70,995✔
4289
      if (rt != NULL) {
70,995✔
4290
         VCODE_ASSERT(rt->kind == VCODE_STAMP_INT, "must be integer stamp");
17,455✔
4291
         low = MAX(low, rt->u.intg.low);
17,455✔
4292
         high = MIN(high, rt->u.intg.high);
17,455✔
4293
      }
4294

4295
      vstamp_t *bt = vcode_stamp_data(stamp);
70,995✔
4296
      if (bt != NULL) {
70,995✔
4297
         VCODE_ASSERT(bt->kind == VCODE_STAMP_INT, "must be integer stamp");
30,037✔
4298
         low = MAX(low, bt->u.intg.low);
30,037✔
4299
         high = MIN(high, bt->u.intg.high);
30,037✔
4300
      }
4301

4302
      stamp = vstamp_int(low, high);
70,995✔
4303
   }
4304

4305
   op->result = vcode_add_reg(type, stamp);
72,162✔
4306

4307
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
127,469✔
4308
      if (from == allowed[i][0] && to == allowed[i][1])
127,469✔
4309
         return op->result;
4310
   }
4311

UNCOV
4312
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4313
}
4314

4315
void emit_return(vcode_reg_t reg)
79,999✔
4316
{
4317
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
79,999✔
4318
   if (reg != VCODE_INVALID_REG) {
79,999✔
4319
      vcode_add_arg(op, reg);
31,165✔
4320

4321
      const vtype_kind_t rkind = vcode_reg_kind(reg);
31,165✔
4322
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY)
31,165✔
4323
         vcode_heap_allocate(reg);
5,715✔
4324

4325
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
31,165✔
4326
                   || active_unit->kind == VCODE_UNIT_THUNK
4327
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4328
                   "returning value fron non-function unit");
4329
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
31,165✔
4330
                    && rkind == VCODE_TYPE_INT)
4331
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4332
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4333
                       && rkind == VCODE_TYPE_ACCESS),
4334
                   "return value incorrect type");
4335
   }
4336
}
79,999✔
4337

4338
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
12,201✔
4339
                         vcode_reg_t values, vcode_reg_t reject,
4340
                         vcode_reg_t after)
4341
{
4342
   int64_t nconst;
12,201✔
4343
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
12,201✔
4344
      emit_comment("Skip empty waveform");
12✔
4345
      return;
12✔
4346
   }
4347

4348
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
12,189✔
4349
   vcode_add_arg(op, nets);
12,189✔
4350
   vcode_add_arg(op, nnets);
12,189✔
4351
   vcode_add_arg(op, values);
12,189✔
4352
   vcode_add_arg(op, reject);
12,189✔
4353
   vcode_add_arg(op, after);
12,189✔
4354

4355
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
12,189✔
4356
                "sched_waveform target is not signal");
4357
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
12,189✔
4358
                "sched_waveform net count is not offset type");
4359
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
12,189✔
4360
                "signal cannot be values argument for sched_waveform");
4361
}
4362

4363
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
93✔
4364
{
4365
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
93✔
4366
   vcode_add_arg(op, nets);
93✔
4367
   vcode_add_arg(op, nnets);
93✔
4368
   vcode_add_arg(op, values);
93✔
4369

4370
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
93✔
4371
                "force target is not signal");
4372
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
93✔
4373
                "force net count is not offset type");
4374
}
93✔
4375

4376
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
56✔
4377
{
4378
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
56✔
4379
   vcode_add_arg(op, nets);
56✔
4380
   vcode_add_arg(op, nnets);
56✔
4381

4382
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
56✔
4383
                "release target is not signal");
4384
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
56✔
4385
                "release net count is not offset type");
4386
}
56✔
4387

4388
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
32✔
4389
                     vcode_reg_t after)
4390
{
4391
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
32✔
4392
   vcode_add_arg(op, nets);
32✔
4393
   vcode_add_arg(op, nnets);
32✔
4394
   vcode_add_arg(op, reject);
32✔
4395
   vcode_add_arg(op, after);
32✔
4396

4397
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
32✔
4398
                "disconnect target is not signal");
4399
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
32✔
4400
                "disconnect net count is not offset type");
4401
}
32✔
4402

4403
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
44,328✔
4404
{
4405
   int64_t tconst;
44,328✔
4406
   if (vcode_reg_const(test, &tconst)) {
44,328✔
4407
      emit_jump(!!tconst ? btrue : bfalse);
5,321✔
4408
      return;
2,713✔
4409
   }
4410

4411
   op_t *op = vcode_add_op(VCODE_OP_COND);
41,615✔
4412
   vcode_add_arg(op, test);
41,615✔
4413
   vcode_add_target(op, btrue);
41,615✔
4414
   vcode_add_target(op, bfalse);
41,615✔
4415

4416
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
41,615✔
4417
                "cond test is not a bool");
4418
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
41,615✔
4419
                "invalid cond targets");
4420
}
4421

4422
vcode_reg_t emit_neg(vcode_reg_t lhs)
8,767✔
4423
{
4424
   int64_t lconst;
8,767✔
4425
   if (vcode_reg_const(lhs, &lconst))
8,767✔
UNCOV
4426
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4427

4428
   op_t *op = vcode_add_op(VCODE_OP_NEG);
8,767✔
4429
   vcode_add_arg(op, lhs);
8,767✔
4430
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
8,767✔
4431

4432
   return op->result;
8,767✔
4433
}
4434

4435
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
611✔
4436
{
4437
   int64_t lconst;
611✔
4438
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
611✔
UNCOV
4439
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4440

4441
   reg_t *lhs_r = vcode_reg_data(lhs);
611✔
4442

4443
   vstamp_t *s = vcode_stamp_data(lhs_r->stamp);
611✔
4444
   if (s != NULL && s->kind == VCODE_STAMP_INT && s->u.intg.low >= 0)
611✔
4445
      return emit_neg(lhs);   // Cannot overflow
274✔
4446

4447
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
337✔
4448
   vcode_add_arg(op, lhs);
337✔
4449
   vcode_add_arg(op, locus);
337✔
4450

4451
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
337✔
4452
                "locus argument to trap neg must be a debug locus");
4453
   VCODE_ASSERT(vtype_kind(lhs_r->type) == VCODE_TYPE_INT,
337✔
4454
                "trapping neg may only be used with integer types");
4455

4456
   return (op->result = vcode_add_reg(lhs_r->type, VCODE_INVALID_STAMP));
337✔
4457
}
4458

4459
vcode_reg_t emit_abs(vcode_reg_t lhs)
894✔
4460
{
4461
   int64_t lconst;
894✔
4462
   if (vcode_reg_const(lhs, &lconst))
894✔
4463
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4464

4465
   op_t *op = vcode_add_op(VCODE_OP_ABS);
893✔
4466
   vcode_add_arg(op, lhs);
893✔
4467
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
893✔
4468

4469
   return op->result;
893✔
4470
}
4471

4472
void emit_comment(const char *fmt, ...)
122,462✔
4473
{
4474
#ifndef NDEBUG
4475
   va_list ap;
122,462✔
4476
   va_start(ap, fmt);
122,462✔
4477

4478
   char *buf = xvasprintf(fmt, ap);
122,462✔
4479
   for (char *p = buf + strlen(buf) - 1;
122,462✔
4480
        p >= buf && isspace_iso88591(*p); p--)
122,462✔
UNCOV
4481
      *p = '\0';
×
4482

4483
   vcode_add_op(VCODE_OP_COMMENT)->comment = buf;
122,462✔
4484
   va_end(ap);
122,462✔
4485
#endif
4486
}
122,462✔
4487

4488
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
25,204✔
4489
                        vcode_reg_t rfalse)
4490
{
4491
   int64_t tconst;
25,204✔
4492
   if (vcode_reg_const(test, &tconst))
25,204✔
4493
      return !!tconst ? rtrue : rfalse;
6,421✔
4494
   else if (rtrue == rfalse)
18,783✔
4495
      return rtrue;
4496

4497
   // Find a previous identical select
4498
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
417,506✔
4499
      if (other->args.items[0] == test && other->args.items[1] == rtrue
16,142✔
4500
          && other->args.items[2] == rfalse)
840✔
4501
         return other->result;
707✔
4502
   }
4503

4504
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
17,845✔
4505
   vcode_add_arg(op, test);
17,845✔
4506
   vcode_add_arg(op, rtrue);
17,845✔
4507
   vcode_add_arg(op, rfalse);
17,845✔
4508
   op->result = vcode_add_reg(vcode_reg_type(rtrue), VCODE_INVALID_STAMP);
17,845✔
4509

4510
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
17,845✔
4511
                "select test must have bool type");
4512
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
17,845✔
4513
                "select arguments are not the same type");
4514

4515
   return op->result;
17,845✔
4516
}
4517

4518
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
589✔
4519
{
4520
   switch (op) {
589✔
4521
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
60✔
4522
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
465✔
4523
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
16✔
4524
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
16✔
4525
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
16✔
4526
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
16✔
UNCOV
4527
   default:
×
4528
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
4529
   }
4530
}
4531

4532
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
9,757✔
4533
{
4534
   vcode_type_t vtbool = vtype_bool();
9,757✔
4535

4536
   int64_t lconst, rconst;
9,757✔
4537
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
9,757✔
4538
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
9,757✔
4539
   if (l_is_const && r_is_const) {
9,757✔
4540
      switch (op) {
8✔
UNCOV
4541
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
UNCOV
4542
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
UNCOV
4543
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
×
4544
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
8✔
UNCOV
4545
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
UNCOV
4546
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
UNCOV
4547
      default:
×
4548
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4549
      }
4550
   }
4551
   else if (l_is_const)
9,749✔
4552
      return emit_logical_identity(op, rhs, !!lconst);
456✔
4553
   else if (r_is_const)
9,293✔
4554
      return emit_logical_identity(op, lhs, !!rconst);
133✔
4555
   else if (lhs == rhs) {
9,160✔
4556
      switch (op) {
36✔
4557
      case VCODE_OP_AND:
4558
      case VCODE_OP_OR:
4559
         return lhs;
4560
      case VCODE_OP_NAND:
8✔
4561
      case VCODE_OP_NOR:
4562
         return emit_not(lhs);
8✔
4563
      case VCODE_OP_XOR:
4✔
4564
         return emit_const(vtbool, 0);
4✔
UNCOV
4565
      case VCODE_OP_XNOR:
×
UNCOV
4566
         return emit_const(vtbool, 1);
×
UNCOV
4567
      default:
×
4568
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4569
      }
4570
   }
4571

4572
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
9,124✔
4573

4574
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
9,124✔
4575
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4576
                "arguments to %s are not boolean", vcode_op_string(op));
4577

4578
   return result;
4579
}
4580

4581
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
3,138✔
4582
{
4583
   return emit_logical(VCODE_OP_OR, lhs, rhs);
3,138✔
4584
}
4585

4586
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
6,323✔
4587
{
4588
   return emit_logical(VCODE_OP_AND, lhs, rhs);
6,323✔
4589
}
4590

4591
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
65✔
4592
{
4593
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
65✔
4594
}
4595

4596
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
66✔
4597
{
4598
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
66✔
4599
}
4600

4601
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
92✔
4602
{
4603
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
92✔
4604
}
4605

4606
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
73✔
4607
{
4608
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
73✔
4609
}
4610

4611
vcode_reg_t emit_not(vcode_reg_t arg)
3,408✔
4612
{
4613
   int64_t cval;
3,408✔
4614
   if (vcode_reg_const(arg, &cval))
3,408✔
4615
      return emit_const(vtype_bool(), !cval);
36✔
4616

4617
   op_t *op = vcode_add_op(VCODE_OP_NOT);
3,372✔
4618
   vcode_add_arg(op, arg);
3,372✔
4619

4620
   vcode_type_t vtbool = vtype_bool();
3,372✔
4621
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
3,372✔
4622
                "argument to not is not boolean");
4623

4624
   return (op->result = vcode_add_reg(vtbool, VCODE_INVALID_STAMP));
3,372✔
4625
}
4626

4627
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
62,785✔
4628
{
4629
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
2,432,986✔
4630
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
211,018✔
4631
         bool match = true;
4632
         for (int i = 0; match && i < ndims; i++) {
29,691✔
4633
            match = other->args.items[i*3 + 1] == dims[i].left
14,888✔
4634
               && other->args.items[i*3 + 2] == dims[i].right
12,227✔
4635
               && other->args.items[i*3 + 3] == dims[i].dir;
26,745✔
4636
         }
4637
         if (match)
14,803✔
4638
            return other->result;
11,772✔
4639
      }
4640
   }
4641

4642
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
51,013✔
4643
   vcode_add_arg(op, data);
51,013✔
4644
   for (int i = 0; i < ndims; i++) {
102,932✔
4645
      vcode_add_arg(op, dims[i].left);
51,919✔
4646
      vcode_add_arg(op, dims[i].right);
51,919✔
4647
      vcode_add_arg(op, dims[i].dir);
51,919✔
4648
   }
4649

4650
   vcode_type_t ptr_type = vcode_reg_type(data);
51,013✔
4651
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
51,013✔
4652
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
51,013✔
4653
                "wrapped data is not pointer or signal");
4654

4655
#ifdef DEBUG
4656
   for (int i = 0; i < ndims; i++) {
102,932✔
4657
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
51,919✔
4658
                   "dimension %d left bound must be scalar", i + 1);
4659
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
51,919✔
4660
                   "dimension %d right bound must be scalar", i + 1);
4661
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
51,919✔
4662
                   "dimension %d direction must be bool", i + 1);
4663
   }
4664
#endif
4665

4666
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
102,026✔
4667
      ? vtype_pointed(ptr_type) : ptr_type;
51,013✔
4668

4669
   op->result = vcode_add_reg(vtype_uarray(ndims, elem), vcode_reg_stamp(data));
51,013✔
4670

4671
   return op->result;
51,013✔
4672
}
4673

4674
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
140,453✔
4675
                                  vcode_reg_t array, unsigned dim,
4676
                                  unsigned arg_index)
4677
{
4678
   // Reuse any previous operation in this block with the same arguments
4679
   VCODE_FOR_EACH_OP(other) {
1,664,542✔
4680
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,603,185✔
4681
          && (rtype == VCODE_INVALID_TYPE
32,964✔
4682
              || vtype_eq(rtype, vcode_reg_type(other->result))))
14,155✔
4683
         return other->result;
32,964✔
4684
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,570,221✔
4685
         return other->args.items[1 + (dim * 3) + arg_index];
46,132✔
4686
   }
4687

4688
   op_t *op = vcode_add_op(o);
61,357✔
4689
   vcode_add_arg(op, array);
61,357✔
4690
   op->dim = dim;
61,357✔
4691

4692
   vcode_type_t atype = vcode_reg_type(array);
61,357✔
4693
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
61,357✔
4694
                "cannot use %s with non-uarray type", vcode_op_string(o));
4695

4696
   vtype_t *vt = vcode_type_data(atype);
61,357✔
4697
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
61,357✔
4698

4699
   if (rtype == VCODE_INVALID_TYPE)
61,357✔
4700
      rtype = vtype_offset();
39,610✔
4701

4702
   return (op->result = vcode_add_reg(rtype, VCODE_INVALID_STAMP));
61,357✔
4703
}
4704

4705
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
51,746✔
4706
{
4707
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
51,746✔
4708
                         array, dim, 0);
4709
}
4710

4711
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
37,291✔
4712
{
4713
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
37,291✔
4714
                         array, dim, 1);
4715
}
4716

4717
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
51,416✔
4718
{
4719
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
51,416✔
4720
                         array, dim, 2);
4721
}
4722

4723
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
61,858✔
4724
{
4725
   VCODE_FOR_EACH_OP(other) {
1,033,506✔
4726
      if (other->kind == VCODE_OP_UARRAY_LEN) {
1,003,859✔
4727
         if (other->args.items[0] == array && other->dim == dim)
64,199✔
4728
            return other->result;
12,591✔
4729
      }
4730
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
939,660✔
4731
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
19,620✔
4732
                      "array dimension %d out of bounds", dim);
4733

4734
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
19,620✔
4735
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
19,620✔
4736
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
19,620✔
4737
         return emit_range_length(left_reg, right_reg, dir_reg);
19,620✔
4738
      }
4739
   }
4740

4741
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
29,647✔
4742
   vcode_add_arg(op, array);
29,647✔
4743
   op->dim = dim;
29,647✔
4744

4745
   vcode_type_t atype = vcode_reg_type(array);
29,647✔
4746
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
29,647✔
4747
                "cannot use uarray len with non-uarray type");
4748

4749
   vtype_t *vt = vcode_type_data(atype);
29,647✔
4750
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
29,647✔
4751

4752
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
29,647✔
4753

4754
   return op->result;
29,647✔
4755
}
4756

4757
vcode_reg_t emit_unwrap(vcode_reg_t array)
47,965✔
4758
{
4759
   VCODE_FOR_EACH_OP(other) {
2,436,192✔
4760
      if (other->kind == VCODE_OP_WRAP && other->result == array)
2,401,578✔
4761
         return other->args.items[0];
10,973✔
4762
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
2,390,605✔
4763
         return other->result;
2,378✔
4764
   }
4765

4766
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
34,614✔
4767
   vcode_add_arg(op, array);
34,614✔
4768

4769
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
34,614✔
4770
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
34,614✔
4771
                "unwrap can only only be used with uarray types");
4772

4773
   vcode_type_t elem = vt->elem;
34,614✔
4774

4775
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
34,614✔
4776
      ? elem : vtype_pointer(elem);
34,614✔
4777

4778
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
34,614✔
4779
}
4780

4781
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
48,368✔
4782
                            vcode_reg_t dir)
4783
{
4784
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
2,563,554✔
UNCOV
4785
      if (other->args.items[0] == left
×
UNCOV
4786
          && other->args.items[1] == right
×
UNCOV
4787
          && other->args.items[2] == dir)
×
UNCOV
4788
         return other->result;
×
4789
   }
4790

4791
   int64_t dir_const, l_low, l_high, r_low, r_high;
48,368✔
4792
   if (vcode_reg_const(dir, &dir_const)
48,368✔
4793
       && vcode_reg_bounds(left, &l_low, &l_high)
44,180✔
4794
       && vcode_reg_bounds(right, &r_low, &r_high)) {
44,180✔
4795

4796
      if (dir_const == RANGE_TO && l_low > r_high)
44,180✔
4797
         return emit_const(vtype_bool(), 1);
84✔
4798
      else if (dir_const == RANGE_TO && l_high <= r_low)
44,096✔
4799
         return emit_const(vtype_bool(), 0);
33,163✔
4800
      else if (dir_const == RANGE_DOWNTO && r_low > l_high)
10,933✔
4801
         return emit_const(vtype_bool(), 1);
992✔
4802
      else if (dir_const == RANGE_DOWNTO && r_high <= l_low)
9,941✔
4803
         return emit_const(vtype_bool(), 0);
2,640✔
4804
      else if (dir_const == RANGE_TO)
7,301✔
4805
         return emit_cmp(VCODE_CMP_GT, left, right);
3,850✔
4806
      else
4807
         return emit_cmp(VCODE_CMP_GT, right, left);
3,451✔
4808
   }
4809

4810
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
4,188✔
4811
   vcode_add_arg(op, left);
4,188✔
4812
   vcode_add_arg(op, right);
4,188✔
4813
   vcode_add_arg(op, dir);
4,188✔
4814

4815
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
4,188✔
4816
                "range left and right have different types");
4817
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
4,188✔
4818
                "dir argument to range length is not int");
4819

4820
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
4,188✔
4821
}
4822

4823
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
19,670✔
4824
                              vcode_reg_t dir)
4825
{
4826
   vcode_reg_t left_array = VCODE_INVALID_REG,
19,670✔
4827
      right_array = VCODE_INVALID_REG,
19,670✔
4828
      dir_array = VCODE_INVALID_REG;
19,670✔
4829
   int left_dim = -1, right_dim = -1, dir_dim = -1;
19,670✔
4830

4831
   VCODE_FOR_EACH_OP(other) {
394,419✔
4832
      if (other->kind == VCODE_OP_RANGE_LENGTH
381,863✔
4833
          && other->args.items[0] == left
9,735✔
4834
          && other->args.items[1] == right
7,547✔
4835
          && other->args.items[2] == dir)
7,114✔
4836
         return other->result;
7,114✔
4837
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
374,749✔
4838
         left_array = other->args.items[0];
501✔
4839
         left_dim = other->dim;
501✔
4840
      }
4841
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
374,248✔
4842
         right_array = other->args.items[0];
501✔
4843
         right_dim = other->dim;
501✔
4844
      }
4845
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
373,747✔
4846
         dir_array = other->args.items[0];
1,026✔
4847
         dir_dim = other->dim;
1,026✔
4848
      }
4849
   }
4850

4851
   if (left_array != VCODE_INVALID_REG && left_array == right_array
12,556✔
4852
       && right_array == dir_array && left_dim == right_dim
501✔
4853
       && right_dim == dir_dim)
501✔
4854
      return emit_uarray_len(left_array, left_dim);
501✔
4855

4856
   int64_t lconst, rconst, dconst;
12,055✔
4857
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
12,055✔
4858
       && vcode_reg_const(right, &rconst)) {
6,578✔
4859

4860
      int64_t diff;
2,726✔
4861
      if (dconst == RANGE_TO)
2,726✔
4862
         diff = rconst - lconst;
2,289✔
4863
      else
4864
         diff = lconst - rconst;
437✔
4865

4866
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
2,726✔
4867
   }
4868

4869
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
9,329✔
4870
   vcode_add_arg(op, left);
9,329✔
4871
   vcode_add_arg(op, right);
9,329✔
4872
   vcode_add_arg(op, dir);
9,329✔
4873

4874
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
9,329✔
4875
                "range left and right have different types");
4876
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
9,329✔
4877
                "dir argument to range length is not int");
4878

4879
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
9,329✔
4880

4881
   return op->result;
9,329✔
4882
}
4883

4884
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
78,292✔
4885
{
4886
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
715,371✔
4887
      if (other->hops == hops && other->address == var)
99,502✔
4888
         return other->result;
16,816✔
4889
   }
4890

4891
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
61,476✔
4892
   op->hops    = hops;
61,476✔
4893
   op->address = var;
61,476✔
4894

4895
   VCODE_ASSERT(hops > 0, "invalid hop count");
61,476✔
4896

4897
   vcode_unit_t vu = active_unit;
61,476✔
4898
   for (int i = 0; i < hops; i++) {
136,026✔
4899
      vu = vu->context;
74,550✔
4900
      VCODE_ASSERT(vu, "hop count is greater than depth");
74,550✔
4901
   }
4902

4903
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
61,476✔
4904

4905
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
61,476✔
4906

4907
   return op->result;
61,476✔
4908
}
4909

4910
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
27,396✔
4911
                             vcode_reg_t size, vcode_reg_t value,
4912
                             vcode_reg_t flags, vcode_reg_t locus,
4913
                             vcode_reg_t offset)
4914
{
4915
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
27,396✔
4916
   vcode_add_arg(op, count);
27,396✔
4917
   vcode_add_arg(op, size);
27,396✔
4918
   vcode_add_arg(op, value);
27,396✔
4919
   vcode_add_arg(op, flags);
27,396✔
4920
   vcode_add_arg(op, locus);
27,396✔
4921
   if (offset != VCODE_INVALID_REG)
27,396✔
4922
      vcode_add_arg(op, offset);
9,653✔
4923

4924
   vcode_type_t vtype = vcode_reg_type(value);
27,396✔
4925
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
27,396✔
4926
   VCODE_ASSERT(vtype_eq(vtype, type)
27,396✔
4927
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4928
                "init signal value type does not match signal type");
4929
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
27,396✔
4930
                "locus argument to init signal must be a debug locus");
4931
   VCODE_ASSERT(offset == VCODE_INVALID_REG
27,396✔
4932
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4933
                "init signal offset argument must have pointer type");
4934

4935
   vcode_type_t stype = vtype_signal(type);
27,396✔
4936
   return (op->result = vcode_add_reg(stype, VCODE_INVALID_STAMP));
27,396✔
4937
}
4938

4939
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
5,776✔
4940
{
4941
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
5,776✔
4942
   vcode_add_arg(op, signal);
5,776✔
4943
   vcode_add_arg(op, resolution);
5,776✔
4944

4945
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
5,776✔
4946
                "signal argument has wrong type");
4947

4948
   vcode_type_t rtype = vcode_reg_type(resolution);
5,776✔
4949
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
5,776✔
4950
                "resolution wrapper argument must be pointer");
4951
   VCODE_ASSERT(vtype_kind(vtype_pointed(rtype)) == VCODE_TYPE_RESOLUTION,
5,776✔
4952
                "resolution wrapper argument has wrong type");
4953
}
5,776✔
4954

4955
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
127✔
4956
                                 vcode_reg_t size, vcode_reg_t locus,
4957
                                 vcode_reg_t kind, vcode_reg_t closure,
4958
                                 vcode_reg_t delay)
4959
{
4960
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
127✔
4961
   vcode_add_arg(op, count);
127✔
4962
   vcode_add_arg(op, size);
127✔
4963
   vcode_add_arg(op, locus);
127✔
4964
   vcode_add_arg(op, kind);
127✔
4965
   vcode_add_arg(op, closure);
127✔
4966
   vcode_add_arg(op, delay);
127✔
4967

4968
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
127✔
4969
                "count argument to implicit signal is not offset");
4970
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
127✔
4971
                "kind argument to implicit signal is not offset");
4972
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
127✔
4973
                "closure argument to implicit signal is not a closure");
4974
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
127✔
4975
                "locus argument to implicit signal must be a debug locus");
4976
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
127✔
4977
                "delay argument to implicit signal must be time");
4978

4979
   vcode_type_t stype = vtype_signal(type);
127✔
4980
   return (op->result = vcode_add_reg(stype, VCODE_INVALID_REG));
127✔
4981
}
4982

4983
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
9,056✔
4984
{
4985
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
9,056✔
4986
   vcode_add_arg(op, src);
9,056✔
4987
   vcode_add_arg(op, dst);
9,056✔
4988
   vcode_add_arg(op, count);
9,056✔
4989

4990
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
9,056✔
4991
                "src argument to map signal is not a signal");
4992
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
9,056✔
4993
                "dst argument to map signal is not a signal");
4994
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
9,056✔
4995
                "count argument type to map signal is not offset");
4996
}
9,056✔
4997

4998
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
319✔
4999
{
5000
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
319✔
5001
   vcode_add_arg(op, src);
319✔
5002
   vcode_add_arg(op, dst);
319✔
5003
   vcode_add_arg(op, count);
319✔
5004

5005
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
319✔
5006
                "dst argument to map const is not a signal");
5007
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
319✔
5008
                "count argument type to map const is not offset");
5009
}
319✔
5010

5011
void emit_map_implicit(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
95✔
5012
{
5013
   op_t *op = vcode_add_op(VCODE_OP_MAP_IMPLICIT);
95✔
5014
   vcode_add_arg(op, src);
95✔
5015
   vcode_add_arg(op, dst);
95✔
5016
   vcode_add_arg(op, count);
95✔
5017

5018
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
95✔
5019
                "src argument to map implicit is not a signal");
5020
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
95✔
5021
                "dst argument to map implicit is not a signal");
5022
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
95✔
5023
                "count argument type to map implicit is not offset");
5024
}
95✔
5025

5026
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
10,125✔
5027
{
5028
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
125,658✔
5029
      if (other->args.items[0] == target && other->args.items[1] == count)
16,945✔
5030
         return;
5031
   }
5032

5033
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
10,121✔
5034
   vcode_add_arg(op, target);
10,121✔
5035
   vcode_add_arg(op, count);
10,121✔
5036

5037
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
10,121✔
5038
                "target argument to drive signal is not a signal");
5039
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
10,121✔
5040
                "count argument type to drive signal is not offset");
5041
}
5042

5043
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
649✔
5044
                          vcode_reg_t count, vcode_reg_t reject,
5045
                          vcode_reg_t after)
5046
{
5047
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
649✔
5048
   vcode_add_arg(op, target);
649✔
5049
   vcode_add_arg(op, source);
649✔
5050
   vcode_add_arg(op, count);
649✔
5051
   vcode_add_arg(op, reject);
649✔
5052
   vcode_add_arg(op, after);
649✔
5053

5054
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
649✔
5055
                "target argument to transfer signal is not a signal");
5056
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
649✔
5057
                "count argument type to transfer signal is not offset");
5058
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
649✔
5059
                "source argument to transfer signal is not a signal");
5060
}
649✔
5061

5062
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
10,514✔
5063
                                    vcode_reg_t nlits)
5064
{
5065
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
162,329✔
5066
      if (other->args.items[0] == closure && other->args.items[1] == nlits)
21,989✔
UNCOV
5067
         return other->result;
×
5068
   }
5069

5070
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
10,514✔
5071
                "first argument to resolution wrapper must be closure");
5072

5073
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
10,514✔
5074
   vcode_add_arg(op, closure);
10,514✔
5075
   vcode_add_arg(op, nlits);
10,514✔
5076

5077
   return (op->result = vcode_add_reg(vtype_resolution(type),
10,514✔
5078
                                      VCODE_INVALID_STAMP));
5079
}
5080

5081
vcode_reg_t emit_closure(ident_t func, vcode_type_t rtype,
11,243✔
5082
                         const vcode_reg_t *args, int nargs)
5083
{
5084
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
169,953✔
5085
      if (other->func != func || other->args.count != nargs)
22,361✔
5086
         continue;
22,361✔
5087

5088
      bool match = true;
UNCOV
5089
      for (int i = 0; i < nargs; i++)
×
UNCOV
5090
         match &= other->args.items[i] == args[i];
×
5091

UNCOV
5092
      if (match)
×
UNCOV
5093
         return other->result;
×
5094
   }
5095

5096
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
11,243✔
5097
   op->func = func;
11,243✔
5098
   for (int i = 0; i < nargs; i++)
23,262✔
5099
      vcode_add_arg(op, args[i]);
12,019✔
5100

5101
   return (op->result = vcode_add_reg(vtype_closure(rtype),
11,243✔
5102
                                      VCODE_INVALID_STAMP));
5103
}
5104

5105
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
60,211✔
5106
{
5107
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
122,049✔
5108
      if (other->func == name)
50,412✔
5109
         return other->result;
23,733✔
5110
   }
5111

5112
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
36,478✔
5113
   op->func = name;
36,478✔
5114
   if (context != VCODE_INVALID_REG)
36,478✔
5115
      vcode_add_arg(op, context);
310✔
5116

5117
   VCODE_ASSERT(context == VCODE_INVALID_REG
36,478✔
5118
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5119
                "invalid protected init context argument");
5120
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
36,478✔
5121
                || active_unit->kind == VCODE_UNIT_PACKAGE
5122
                || active_unit->kind == VCODE_UNIT_THUNK,
5123
                "cannot use package init here");
5124
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
36,478✔
5125

5126
   return (op->result = vcode_add_reg(vtype_context(name),
36,478✔
5127
                                      VCODE_INVALID_STAMP));
5128
}
5129

5130
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
1,043✔
5131
                                vcode_reg_t path_name, vcode_reg_t inst_name)
5132
{
5133
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
1,043✔
5134
   vcode_add_arg(op, context);
1,043✔
5135
   op->func = vtype_name(type);
1,043✔
5136

5137
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
1,043✔
5138
      vcode_add_arg(op, path_name);
817✔
5139
      vcode_add_arg(op, inst_name);
817✔
5140

5141
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
817✔
5142
                   "path name argument must be uarray");
5143
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
817✔
5144
                   "inst name argument must be uarray");
5145
   }
5146

5147
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
1,043✔
5148
                "protected init type must be context");
5149
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
1,043✔
5150
                "invalid protected init context argument");
5151

5152
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
1,043✔
5153
}
5154

5155
void emit_process_init(vcode_reg_t closure, vcode_reg_t locus)
602✔
5156
{
5157
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
602✔
5158
   vcode_add_arg(op, closure);
602✔
5159
   vcode_add_arg(op, locus);
602✔
5160

5161
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
602✔
5162
                "closure argument to process init must be a closure");
5163
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
602✔
5164
                "locus argument to process init must be a debug locus");
5165
}
602✔
5166

5167
void emit_protected_free(vcode_reg_t obj)
611✔
5168
{
5169
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
611✔
5170
   vcode_add_arg(op, obj);
611✔
5171

5172
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
611✔
5173
                "protected object type must be context");
5174
}
611✔
5175

5176
vcode_reg_t emit_context_upref(int hops)
29,930✔
5177
{
5178
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
219,895✔
5179
      if (other->hops == hops)
14,519✔
5180
         return other->result;
14,450✔
5181
   }
5182

5183
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
15,480✔
5184
   op->hops = hops;
15,480✔
5185

5186
   VCODE_ASSERT(hops >= 0, "invalid hop count");
15,480✔
5187

5188
   vcode_unit_t vu = active_unit;
15,480✔
5189
   for (int i = 0; i < hops; i++) {
25,918✔
5190
      vu = vu->context;
10,438✔
5191
      VCODE_ASSERT(vu, "hop count is greater than depth");
10,438✔
5192
   }
5193

5194
   return (op->result = vcode_add_reg(vtype_context(vu->name),
15,480✔
5195
                                      VCODE_INVALID_STAMP));
5196
}
5197

5198
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
911✔
5199
                                    vcode_reg_t len)
5200
{
5201
   op_t *op = vcode_add_op(opkind);
911✔
5202
   vcode_add_arg(op, nets);
911✔
5203
   vcode_add_arg(op, len);
911✔
5204

5205
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
911✔
5206
                "argument to %s is not a signal", vcode_op_string(opkind));
5207

5208
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
911✔
5209
}
5210

5211
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
622✔
5212
{
5213
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
622✔
5214
}
5215

5216
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
289✔
5217
{
5218
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
289✔
5219
}
5220

5221
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
56,385✔
5222
{
5223
   // Try scanning backwards through the block for another record ref
5224
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
4,335,063✔
5225
      if (other->args.items[0] == record && other->field == field)
800,877✔
5226
         return other->result;
6,057✔
5227
   }
5228

5229
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
50,328✔
5230
   op->field = field;
50,328✔
5231
   vcode_add_arg(op, record);
50,328✔
5232

5233
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
50,328✔
5234

5235
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
50,328✔
5236
                "argument to record ref must be a pointer");
5237

5238
   vtype_t *rtype = vcode_type_data(rptype->pointed);
50,328✔
5239
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
50,328✔
5240
                "argument must be pointer to record or record signal");
5241

5242
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
50,328✔
5243

5244
   vcode_type_t field_type  = rtype->fields.items[field];
50,328✔
5245
   vcode_type_t result_type = field_type;
50,328✔
5246

5247
   const vtype_kind_t fkind = vtype_kind(field_type);
50,328✔
5248
   if (fkind == VCODE_TYPE_CARRAY)
50,328✔
5249
      result_type = vtype_elem(field_type);
7,105✔
5250
   else if (fkind == VCODE_TYPE_UARRAY)
5251
      result_type = field_type;
5252

5253
   op->result = vcode_add_reg(vtype_pointer(result_type), VCODE_INVALID_STAMP);
50,328✔
5254

5255
   return op->result;
50,328✔
5256
}
5257

5258
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
46,808✔
5259
{
5260
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
2,597,429✔
5261
      if (other->args.items[0] == array && other->args.items[1] == offset)
170,123✔
5262
         return other->result;
1,586✔
5263
   }
5264

5265
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
45,222✔
5266
   vcode_add_arg(op, array);
45,222✔
5267
   vcode_add_arg(op, offset);
45,222✔
5268

5269
   vcode_type_t rtype = vcode_reg_type(array);
45,222✔
5270
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
45,222✔
5271
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5272
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5273
                "argument to array ref must be a pointer or signal");
5274
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
45,222✔
5275
                "array ref offset argument must have offset type");
5276

5277
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
45,222✔
5278
}
5279

5280
vcode_reg_t emit_table_ref(vcode_reg_t array, vcode_reg_t stride,
886✔
5281
                           const vcode_reg_t *args, int nargs)
5282
{
5283
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_TABLE_REF) {
23,514✔
5284
      if (other->args.items[0] != array || other->args.items[1] != stride)
856✔
5285
         continue;
594✔
5286
      else if (other->args.count != nargs + 2)
262✔
UNCOV
5287
         continue;
×
5288

5289
      bool match = true;
5290
      for (int i = 0; i < nargs; i++)
642✔
5291
         match &= (other->args.items[i + 2] == args[i]);
380✔
5292

5293
      if (match)
262✔
5294
         return other->result;
33✔
5295
   }
5296

5297
   op_t *op = vcode_add_op(VCODE_OP_TABLE_REF);
853✔
5298
   vcode_add_arg(op, array);
853✔
5299
   vcode_add_arg(op, stride);
853✔
5300
   for (int i = 0; i < nargs; i++)
2,077✔
5301
      vcode_add_arg(op, args[i]);
1,224✔
5302

5303
   vcode_type_t rtype = vcode_reg_type(array);
853✔
5304
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER
853✔
5305
                && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY,
5306
                "argument to table ref must be a pointer or signal");
5307
   VCODE_ASSERT(vcode_reg_kind(stride) == VCODE_TYPE_OFFSET,
853✔
5308
                "table ref stride argument must have offset type");
5309

5310
   for (int i = 0; i < nargs; i++)
2,077✔
5311
      VCODE_ASSERT(vtype_is_integral(vcode_reg_type(args[i])),
1,224✔
5312
                   "table ref indices must be integral");
5313

5314
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
853✔
5315
}
5316

5317
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
48,460✔
5318
{
5319
   int64_t cconst;
48,460✔
5320
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
48,460✔
5321
       && cconst == 0)
34,685✔
5322
      return;
7,436✔
5323
   else if (dest == src)
47,279✔
5324
      return;
5325

5326
   op_t *op = vcode_add_op(VCODE_OP_COPY);
41,024✔
5327
   vcode_add_arg(op, dest);
41,024✔
5328
   vcode_add_arg(op, src);
41,024✔
5329
   if (count != VCODE_INVALID_REG)
41,024✔
5330
      vcode_add_arg(op, count);
38,637✔
5331

5332
   vcode_type_t dtype = vcode_reg_type(dest);
41,024✔
5333
   vcode_type_t stype = vcode_reg_type(src);
41,024✔
5334

5335
   vtype_kind_t dkind = vtype_kind(dtype);
41,024✔
5336
   vtype_kind_t skind = vtype_kind(stype);
41,024✔
5337

5338
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
41,024✔
5339
                "destination type is not a pointer or access");
5340
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
41,024✔
5341
                "source type is not a pointer or access");
5342
   VCODE_ASSERT(vtype_eq(dtype, stype),
41,024✔
5343
                "source and destination types do not match");
5344
   VCODE_ASSERT(count == VCODE_INVALID_REG
41,024✔
5345
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5346
                "count is not offset type");
5347

5348
   op->type = vtype_pointed(dtype);
41,024✔
5349
}
5350

5351
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
5,923✔
5352
{
5353
   VCODE_FOR_EACH_OP(other) {
82,859✔
5354
      if (other->kind == VCODE_OP_CLEAR_EVENT)
77,008✔
5355
         break;
5356
      else if (other->kind == VCODE_OP_SCHED_EVENT
76,944✔
5357
               && other->args.items[0] == nets
3,602✔
5358
               && other->args.items[1] == n_elems)
12✔
5359
         return;
5360
   }
5361

5362
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
5,915✔
5363
   vcode_add_arg(op, nets);
5,915✔
5364
   vcode_add_arg(op, n_elems);
5,915✔
5365

5366
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
5,915✔
5367
                "nets argument to sched event must be signal");
5368
}
5369

5370
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
729✔
5371
{
5372
   VCODE_FOR_EACH_OP(other) {
3,347✔
5373
      if (other->kind == VCODE_OP_SCHED_EVENT)
2,618✔
5374
         break;
5375
      else if (other->kind == VCODE_OP_CLEAR_EVENT
2,618✔
5376
               && other->args.items[0] == nets
52✔
UNCOV
5377
               && other->args.items[1] == n_elems)
×
5378
         return;
5379
   }
5380

5381
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
729✔
5382
   vcode_add_arg(op, nets);
729✔
5383
   vcode_add_arg(op, n_elems);
729✔
5384

5385
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
729✔
5386
                "nets argument to clear event must be signal");
5387
}
5388

5389
void emit_sched_active(vcode_reg_t nets, vcode_reg_t n_elems)
485✔
5390
{
5391
   op_t *op = vcode_add_op(VCODE_OP_SCHED_ACTIVE);
485✔
5392
   vcode_add_arg(op, nets);
485✔
5393
   vcode_add_arg(op, n_elems);
485✔
5394

5395
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
485✔
5396
                "nets argument to sched active must be signal");
5397
}
485✔
5398

5399
void emit_sched_process(vcode_reg_t delay)
7,060✔
5400
{
5401
   op_t *op = vcode_add_op(VCODE_OP_SCHED_PROCESS);
7,060✔
5402
   vcode_add_arg(op, delay);
7,060✔
5403

5404
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
7,060✔
5405
                "delay must have integer type");
5406
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
7,060✔
5407
                || active_unit->kind == VCODE_UNIT_PROCESS,
5408
                "sched process only allowed in process or procedure");
5409
}
7,060✔
5410

5411
void emit_resume(ident_t func)
1,143✔
5412
{
5413
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
1,143✔
5414
   op->func = func;
1,143✔
5415

5416
   block_t *b = &(active_unit->blocks.items[active_block]);
1,143✔
5417
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
1,143✔
5418
}
1,143✔
5419

5420
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
7,393✔
5421
{
5422
   int64_t lconst;
7,393✔
5423
   if (vcode_reg_const(len, &lconst) && lconst == 0)
7,393✔
5424
      return;
41✔
5425

5426
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
7,352✔
5427
   vcode_add_arg(op, ptr);
7,352✔
5428
   vcode_add_arg(op, value);
7,352✔
5429
   vcode_add_arg(op, len);
7,352✔
5430

5431
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
7,352✔
5432
                "target of memset must have pointer type");
5433
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
7,352✔
5434
                "value of memset must have scalar type");
5435
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
7,352✔
5436
                "length of memset must have offset type");
5437
}
5438

5439
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
867✔
5440
               const vcode_block_t *blocks, int ncases)
5441
{
5442
   int64_t cval1, cval2;
867✔
5443
   bool is_const = vcode_reg_const(value, &cval1);
867✔
5444

5445
   for (int i = 0; i < ncases; i++) {
4,847✔
5446
      bool can_fold = false;
3,980✔
5447
      if (cases[i] == value)
3,980✔
5448
         can_fold = true;
5449
      else if (is_const && vcode_reg_const(cases[i], &cval2))
3,980✔
UNCOV
5450
         can_fold = (cval1 == cval2);
×
5451

UNCOV
5452
      if (can_fold) {
×
UNCOV
5453
         emit_jump(blocks[i]);
×
UNCOV
5454
         return;
×
5455
      }
5456
   }
5457

5458
   if (is_const) {
867✔
UNCOV
5459
      emit_jump(def);
×
UNCOV
5460
      return;
×
5461
   }
5462

5463
   op_t *op = vcode_add_op(VCODE_OP_CASE);
867✔
5464
   vcode_add_arg(op, value);
867✔
5465
   vcode_add_target(op, def);
867✔
5466

5467
   for (int i = 0; i < ncases; i++) {
4,847✔
5468
      vcode_add_arg(op, cases[i]);
3,980✔
5469
      vcode_add_target(op, blocks[i]);
3,980✔
5470

5471
#ifdef DEBUG
5472
      for (int j = 0; j < i; j++)
19,620✔
5473
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
15,640✔
5474
#endif
5475
   }
5476
}
5477

5478
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
2,043✔
5479
                    vcode_reg_t kind, vcode_reg_t status)
5480
{
5481
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
2,043✔
5482
   vcode_add_arg(op, file);
2,043✔
5483
   vcode_add_arg(op, name);
2,043✔
5484
   vcode_add_arg(op, length);
2,043✔
5485
   vcode_add_arg(op, kind);
2,043✔
5486
   if (status != VCODE_INVALID_REG)
2,043✔
5487
      vcode_add_arg(op, status);
33✔
5488

5489
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
2,043✔
5490
                "file open first argument must have file pointer type");
5491
}
2,043✔
5492

5493
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
363✔
5494
{
5495
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
363✔
5496
   vcode_add_arg(op, file);
363✔
5497
   vcode_add_arg(op, value);
363✔
5498
   if (length != VCODE_INVALID_REG)
363✔
5499
      vcode_add_arg(op, length);
287✔
5500

5501
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
363✔
5502
                "file write first argument must have file pointer type");
5503
}
363✔
5504

5505
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
120✔
5506
                    vcode_reg_t inlen, vcode_reg_t outlen)
5507
{
5508
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
120✔
5509
   vcode_add_arg(op, file);
120✔
5510
   vcode_add_arg(op, ptr);
120✔
5511
   if (inlen != VCODE_INVALID_REG) {
120✔
5512
      vcode_add_arg(op, inlen);
56✔
5513
      if (outlen != VCODE_INVALID_REG)
56✔
5514
         vcode_add_arg(op, outlen);
44✔
5515
   }
5516

5517
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
120✔
5518
                "file read first argument must have file pointer type");
5519
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
120✔
5520
                "file read pointer argument must have pointer type");
5521
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
120✔
5522
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5523
                "file read outlen argument must have pointer type");
5524
}
120✔
5525

5526
vcode_reg_t emit_null(vcode_type_t type)
19,569✔
5527
{
5528
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
399,971✔
5529
      if (vtype_eq(vcode_reg_type(other->result), type))
12,862✔
5530
         return other->result;
6,380✔
5531
   }
5532

5533
   op_t *op = vcode_add_op(VCODE_OP_NULL);
13,189✔
5534
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
13,189✔
5535

5536
   vtype_kind_t kind = vtype_kind(type);
13,189✔
5537
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
13,189✔
5538
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5539
                "null type must be file, access, context, or pointer");
5540

5541
   return op->result;
5542
}
5543

5544
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
881✔
5545
{
5546
   op_t *op = vcode_add_op(VCODE_OP_NEW);
881✔
5547
   if (length != VCODE_INVALID_REG)
881✔
5548
      vcode_add_arg(op, length);
763✔
5549

5550
   op->result = vcode_add_reg(vtype_access(type), VCODE_INVALID_STAMP);
881✔
5551

5552
   vtype_kind_t kind = vtype_kind(type);
881✔
5553
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
881✔
5554
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5555
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5556
                "new type must be int, real, record, access, or uarray");
5557
   VCODE_ASSERT(length == VCODE_INVALID_REG
881✔
5558
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5559
                "new length must have offset type");
5560

5561
   return op->result;
881✔
5562
}
5563

5564
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
4,042✔
5565
{
5566
   VCODE_FOR_EACH_OP(other) {
167,022✔
5567
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
164,020✔
5568
         return;
5569
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
163,421✔
5570
         return;
5571
   }
5572

5573
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
3,002✔
5574
   vcode_add_arg(op, ptr);
3,002✔
5575
   vcode_add_arg(op, locus);
3,002✔
5576

5577
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
3,002✔
5578
                "null check argument must be an access");
5579
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
3,002✔
5580
                "locus argument to null check must be a debug locus");
5581
}
5582

5583
void emit_deallocate(vcode_reg_t ptr)
469✔
5584
{
5585
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
469✔
5586
   vcode_add_arg(op, ptr);
469✔
5587

5588
   vcode_type_t ptype = vcode_reg_type(ptr);
469✔
5589
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
469✔
5590
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5591
                "deallocate argument must be pointer to access");
5592
}
469✔
5593

5594
vcode_reg_t emit_all(vcode_reg_t reg)
4,923✔
5595
{
5596
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
235,476✔
5597
      if (other->args.items[0] == reg)
14,261✔
5598
         return other->result;
1,040✔
5599
   }
5600

5601
   op_t *op = vcode_add_op(VCODE_OP_ALL);
3,883✔
5602
   vcode_add_arg(op, reg);
3,883✔
5603

5604
   vcode_type_t vtype = vcode_reg_type(reg);
3,883✔
5605

5606
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
3,883✔
5607
                "all argument must be an access");
5608

5609
   vcode_type_t pointed = vtype_pointed(vtype);
3,883✔
5610
   op->result = vcode_add_reg(vtype_pointer(pointed), vcode_reg_stamp(reg));
3,883✔
5611

5612
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
3,883✔
5613
                "cannot dereference opaque type");
5614

5615
   return op->result;
5616
}
5617

5618
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
18,041✔
5619
{
5620
   block_t *b = &(active_unit->blocks.items[active_block]);
18,041✔
5621
   for (int i = b->ops.count - 1; i >= 0; i--) {
431,422✔
5622
      const op_t *other = &(b->ops.items[i]);
414,128✔
5623
      if (other->kind == kind && other->args.items[0] == sig)
414,128✔
5624
         return other->result;
747✔
5625
   }
5626

5627
   op_t *op = vcode_add_op(kind);
17,294✔
5628
   vcode_add_arg(op, sig);
17,294✔
5629

5630
   vcode_type_t stype = vcode_reg_type(sig);
17,294✔
5631
   op->type = stype;
17,294✔
5632

5633
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
17,294✔
5634
                "argument r%d to resolved is not a signal", sig);
5635

5636
   vcode_type_t rtype = vtype_base(stype);
17,294✔
5637

5638
   const vtype_kind_t rkind = vtype_kind(rtype);
17,294✔
5639
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
17,294✔
UNCOV
5640
      rtype = vtype_elem(rtype);
×
5641

5642
   VCODE_ASSERT(vtype_is_scalar(rtype),
17,294✔
5643
                "resolved signal base type must be scalar");
5644

5645
   op->result = vcode_add_reg(vtype_pointer(rtype), vcode_reg_stamp(sig));
17,294✔
5646

5647
   return op->result;
17,294✔
5648
}
5649

5650
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
17,792✔
5651
{
5652
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
17,792✔
5653
}
5654

5655
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
249✔
5656
{
5657
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
249✔
5658
}
5659

5660
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
56✔
5661
{
5662
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
56✔
5663
   vcode_add_arg(op, signal);
56✔
5664
   if (len != VCODE_INVALID_REG)
56✔
5665
      vcode_add_arg(op, len);
12✔
5666

5667
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
56✔
5668
                "signal argument to last event must have signal type");
5669
   VCODE_ASSERT(len == VCODE_INVALID_REG
56✔
5670
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5671
                "length argument to last event must have offset type");
5672

5673
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
56✔
5674
}
5675

5676
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
60✔
5677
{
5678
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
60✔
5679
   vcode_add_arg(op, signal);
60✔
5680
   if (len != VCODE_INVALID_REG)
60✔
5681
      vcode_add_arg(op, len);
8✔
5682

5683
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
60✔
5684
                "signal argument to last active must have signal type");
5685
   VCODE_ASSERT(len == VCODE_INVALID_REG
60✔
5686
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5687
                "length argument to last active must have offset type");
5688

5689
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
60✔
5690
}
5691

5692
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
7,126✔
5693
{
5694
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
7,126✔
5695
   vcode_add_arg(op, signal);
7,126✔
5696
   vcode_add_arg(op, locus);
7,126✔
5697

5698
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
7,126✔
5699
                "signal argument must have signal type");
5700
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
7,126✔
5701
                "locus argument must have debug locus type");
5702
}
7,126✔
5703

5704
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
48✔
5705
{
5706
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
48✔
5707
   vcode_add_arg(op, signal);
48✔
5708
   vcode_add_arg(op, len);
48✔
5709

5710
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
48✔
5711
                "signal argument to last active must have signal type");
5712
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
48✔
5713
                "length argument to last active must have offset type");
5714

5715
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
48✔
5716
}
5717

5718
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
436✔
5719
{
5720
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
436✔
5721
   vcode_add_arg(op, signal);
436✔
5722
   vcode_add_arg(op, len);
436✔
5723

5724
   vcode_type_t signal_type = vcode_reg_type(signal);
436✔
5725

5726
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
436✔
5727
                "signal argument to driving value must have signal type");
5728
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
436✔
5729
                "length argument to driving value must have offset type");
5730

5731
   vcode_type_t base_type = vtype_base(signal_type);
436✔
5732
   op->result = vcode_add_reg(vtype_pointer(base_type), VCODE_INVALID_STAMP);
436✔
5733

5734
   return op->result;
436✔
5735
}
5736

5737
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
53,890✔
5738
                       vcode_reg_t dim)
5739
{
5740
   if (rlen == llen)
53,890✔
5741
      return;
5742

5743
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
283,450✔
5744
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
3,916✔
5745
         return;
5746
   }
5747

5748
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
9,602✔
5749
   vcode_add_arg(op, llen);
9,602✔
5750
   vcode_add_arg(op, rlen);
9,602✔
5751
   vcode_add_arg(op, locus);
9,602✔
5752
   if (dim != VCODE_INVALID_REG)
9,602✔
5753
      vcode_add_arg(op, dim);
36✔
5754

5755
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
9,602✔
5756
                "locus argument to length check must be a debug locus");
5757
}
5758

5759
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
233✔
5760
{
5761
   int64_t cval;
233✔
5762
   if (vcode_reg_const(exp, &cval) && cval >= 0)
233✔
5763
      return;
73✔
5764

5765
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
2,119✔
5766
      if (other->args.items[0] == exp)
20✔
5767
         return;
5768
   }
5769

5770
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
160✔
5771
   vcode_add_arg(op, exp);
160✔
5772
   vcode_add_arg(op, locus);
160✔
5773

5774
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
160✔
5775
                "exp argument to exponent check must be a integer");
5776
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
160✔
5777
                "locus argument to exponent check must be a debug locus");
5778
}
5779

5780
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
3,385✔
5781
{
5782
   int64_t cval;
3,385✔
5783
   if (vcode_reg_const(denom, &cval) && cval != 0)
3,385✔
5784
      return;
3,270✔
5785

5786
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
3,054✔
5787
      if (other->args.items[0] == denom)
64✔
5788
         return;
5789
   }
5790

5791
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
115✔
5792
   vcode_add_arg(op, denom);
115✔
5793
   vcode_add_arg(op, locus);
115✔
5794

5795
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
115✔
5796
                "denom argument to zero check must be a integer");
5797
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
115✔
5798
                "locus argument to zero check must be a debug locus");
5799
}
5800

5801
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
131,069✔
5802
                                   vcode_reg_t right, vcode_reg_t dir)
5803
{
5804
   int64_t dconst;
131,069✔
5805
   if (!vcode_reg_const(dir, &dconst))
131,069✔
5806
      return false;
5807

5808
   int64_t lconst, rconst;
117,823✔
5809
   if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
117,823✔
5810
      const bool is_null = (dconst == RANGE_TO && lconst > rconst)
85,083✔
5811
         || (dconst == RANGE_DOWNTO && rconst > lconst);
174,443✔
5812

5813
      int64_t low, high;
89,361✔
5814
      if (vcode_reg_bounds(reg, &low, &high)) {
89,361✔
5815
         const bool ok_static =
178,722✔
5816
            (dconst == RANGE_TO && low >= lconst && high <= rconst)
85,083✔
5817
            || (dconst == RANGE_DOWNTO && low >= rconst && high <= lconst)
11,772✔
5818
            || (!is_null && (reg == left || reg == right));
97,289✔
5819

5820
         return ok_static;
89,361✔
5821
      }
5822
   }
5823
   else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
28,462✔
5824
      vstamp_t *lbounds = vcode_stamp_data(vcode_reg_data(left)->stamp);
25,652✔
5825
      vstamp_t *rbounds = vcode_stamp_data(vcode_reg_data(right)->stamp);
25,652✔
5826

5827
      assert(lbounds->kind == VCODE_STAMP_REAL);
25,652✔
5828
      assert(rbounds->kind == VCODE_STAMP_REAL);
25,652✔
5829

5830
      double low, high;
25,652✔
5831

5832
      reg_t *rr = vcode_reg_data(reg);
25,652✔
5833
      vstamp_t *bounds = vcode_stamp_data(rr->stamp);
25,652✔
5834
      if (bounds != NULL) {
25,652✔
5835
         assert(bounds->kind == VCODE_STAMP_REAL);
16,844✔
5836
         low = bounds->u.real.low;
16,844✔
5837
         high = bounds->u.real.high;
16,844✔
5838
      }
5839
      else {
5840
         vtype_t *type = vcode_type_data(rr->type);
8,808✔
5841
         assert(type->kind == VCODE_TYPE_REAL);
8,808✔
5842
         low = type->rlow;
8,808✔
5843
         high = type->rhigh;
8,808✔
5844
      }
5845

5846
      if (isfinite(low) && lbounds->u.real.low == -DBL_MAX
25,652✔
5847
          && isfinite(high) && rbounds->u.real.high == DBL_MAX) {
24,702✔
5848
         // Covers the complete double range so can never overflow
5849
         return true;
24,702✔
5850
      }
5851
   }
5852

5853
   return false;
5854
}
5855

5856
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
132,264✔
5857
                              vcode_reg_t left, vcode_reg_t right,
5858
                              vcode_reg_t dir, vcode_reg_t locus,
5859
                              vcode_reg_t hint)
5860
{
5861
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
6,329,863✔
5862
      if (other->args.items[0] == reg && other->args.items[1] == left
25,697✔
5863
          && other->args.items[2] == right && other->args.items[3] == dir)
1,422✔
5864
         return;
5865
   }
5866

5867
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
131,069✔
5868
      emit_comment("Elided bounds check for r%d", reg);
106,135✔
5869
      return;
106,135✔
5870
   }
5871

5872
   op_t *op = vcode_add_op(kind);
24,934✔
5873
   vcode_add_arg(op, reg);
24,934✔
5874
   vcode_add_arg(op, left);
24,934✔
5875
   vcode_add_arg(op, right);
24,934✔
5876
   vcode_add_arg(op, dir);
24,934✔
5877
   vcode_add_arg(op, locus);
24,934✔
5878
   vcode_add_arg(op, hint);
24,934✔
5879

5880
   VCODE_ASSERT(vtype_is_numeric(vcode_reg_type(reg)),
24,934✔
5881
                "argument to bounds check must be numeric");
5882
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
24,934✔
5883
                "locus argument to bounds check must be a debug locus");
5884
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
24,934✔
5885
                "hint argument to bounds check must be a debug locus");
5886
}
5887

5888
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
30,110✔
5889
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5890
{
5891
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
30,110✔
5892
}
30,110✔
5893

5894
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
102,154✔
5895
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5896
{
5897
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
102,154✔
5898
}
102,154✔
5899

5900
void emit_dir_check(vcode_reg_t reg, vcode_reg_t dir, vcode_reg_t locus)
4,453✔
5901
{
5902
   if (reg == dir)
4,453✔
5903
      return;
5904

5905
   op_t *op = vcode_add_op(VCODE_OP_DIR_CHECK);
3,227✔
5906
   vcode_add_arg(op, reg);
3,227✔
5907
   vcode_add_arg(op, dir);
3,227✔
5908
   vcode_add_arg(op, locus);
3,227✔
5909

5910
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
3,227✔
5911
                "locus argument to dir check must be a debug locus");
5912
}
5913

5914
void emit_package_scope(vcode_reg_t locus)
72✔
5915
{
5916
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
72✔
5917
   vcode_add_arg(op, locus);
72✔
5918

5919
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
72✔
5920
                "locus argument to package scope must be a debug locus");
5921
}
72✔
5922

5923
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
1,103✔
5924
{
5925
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
1,103✔
5926
   vcode_add_arg(op, locus);
1,103✔
5927
   op->type = type;
1,103✔
5928

5929
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,103✔
5930
                "locus argument to array scope must be a debug locus");
5931
}
1,103✔
5932

5933
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
2,866✔
5934
{
5935
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
2,866✔
5936
   vcode_add_arg(op, locus);
2,866✔
5937
   op->type = type;
2,866✔
5938

5939
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,866✔
5940
                "locus argument to record scope must be a debug locus");
5941
}
2,866✔
5942

5943
void emit_pop_scope(void)
4,041✔
5944
{
5945
   vcode_add_op(VCODE_OP_POP_SCOPE);
4,041✔
5946
}
4,041✔
5947

5948
vcode_reg_t emit_debug_locus(object_t *obj)
258,961✔
5949
{
5950
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
10,803,696✔
5951
      if (other->object == obj)
1,359,748✔
5952
         return other->result;
25,973✔
5953
   }
5954

5955
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
232,988✔
5956
   op->object = obj;
232,988✔
5957
   op->result = vcode_add_reg(vtype_debug_locus(), VCODE_INVALID_STAMP);
232,988✔
5958

5959
   return op->result;
232,988✔
5960
}
5961

UNCOV
5962
void emit_debug_out(vcode_reg_t reg)
×
5963
{
UNCOV
5964
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
UNCOV
5965
   vcode_add_arg(op, reg);
×
UNCOV
5966
}
×
5967

5968
void emit_cover_stmt(vcode_reg_t counters, uint32_t tag)
1,571✔
5969
{
5970
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,571✔
5971
   vcode_add_arg(op, counters);
1,571✔
5972
   op->tag = tag;
1,571✔
5973

5974
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
1,571✔
5975
                "counters argument must be pointer");
5976
}
1,571✔
5977

5978
void emit_cover_branch(vcode_reg_t counters, uint32_t tag)
683✔
5979
{
5980
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
683✔
5981
   vcode_add_arg(op, counters);
683✔
5982
   op->tag = tag;
683✔
5983

5984
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
683✔
5985
                "counters argument must be pointer");
5986
}
683✔
5987

5988
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
462✔
5989
{
5990
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
462✔
5991
   vcode_add_arg(op, signal);
462✔
5992
   op->tag = tag;
462✔
5993
}
462✔
5994

5995
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
18✔
5996
{
5997
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
18✔
5998
   vcode_add_arg(op, signal);
18✔
5999
   vcode_add_arg(op, low);
18✔
6000
   op->tag = tag;
18✔
6001
}
18✔
6002

6003
void emit_cover_expr(vcode_reg_t counters, uint32_t tag)
1,144✔
6004
{
6005
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
1,144✔
6006
   vcode_add_arg(op, counters);
1,144✔
6007
   op->tag = tag;
1,144✔
6008

6009
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
1,144✔
6010
                "counters argument must be pointer");
6011
}
1,144✔
6012

6013
void emit_unreachable(vcode_reg_t locus)
1,926✔
6014
{
6015
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
1,926✔
6016
   if (locus != VCODE_INVALID_REG)
1,926✔
6017
      vcode_add_arg(op, locus);
163✔
6018
}
1,926✔
6019

6020
vcode_reg_t emit_undefined(vcode_type_t type, vcode_stamp_t stamp)
34✔
6021
{
6022
   active_unit->flags |= UNIT_UNDEFINED;
34✔
6023

6024
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
34✔
6025
   op->result = vcode_add_reg(type, stamp);
34✔
6026

6027
   return op->result;
34✔
6028
}
6029

6030
void emit_debug_info(const loc_t *loc)
3,995,564✔
6031
{
6032
   if (!loc_invalid_p(loc))
3,995,564✔
6033
      vcode_block_data()->last_loc = *loc;
3,964,985✔
6034
}
3,995,564✔
6035

6036
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
13,482✔
6037
{
6038
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
488,686✔
6039
      if (other->args.items[0] == context && other->ident == name)
18,984✔
6040
         return other->result;
6,335✔
6041
   }
6042

6043
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
7,147✔
6044
   vcode_add_arg(op, context);
7,147✔
6045
   op->ident = name;
7,147✔
6046

6047
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
7,147✔
6048
                "first argument to link var must be context");
6049

6050
   vcode_stamp_t stamp = VCODE_INVALID_STAMP;
7,147✔
6051

6052
   if (vtype_kind(type) == VCODE_TYPE_CARRAY)
7,147✔
6053
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)), stamp);
799✔
6054
   else
6055
      op->result = vcode_add_reg(vtype_pointer(type), stamp);
6,348✔
6056

6057
   return op->result;
7,147✔
6058
}
6059

6060
vcode_reg_t emit_link_package(ident_t name)
17,667✔
6061
{
6062
   VCODE_FOR_EACH_OP(other) {
650,984✔
6063
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
642,011✔
6064
         return other->result;
7,769✔
6065
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
634,242✔
6066
         return other->result;
925✔
6067
   }
6068

6069
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
8,973✔
6070
   op->ident = name;
8,973✔
6071

6072
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
8,973✔
6073

6074
   vcode_type_t type = vtype_context(name);
8,973✔
6075
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
8,973✔
6076
}
6077

6078
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
1,136✔
6079
{
6080
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
2,740✔
UNCOV
6081
      if (other->args.items[0] == state)
×
6082
         return;
6083
   }
6084

6085
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
1,136✔
6086
   vcode_add_arg(op, state);
1,136✔
6087
   if (strong != VCODE_INVALID_REG)
1,136✔
6088
      vcode_add_arg(op, strong);
48✔
6089

6090
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
1,136✔
6091
                "state must have integer type");
6092
   VCODE_ASSERT(strong == VCODE_INVALID_REG
1,136✔
6093
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
6094
                "strong argument not is not boolean");
6095
}
6096

6097
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
68✔
6098
                               vcode_reg_t locus, vcode_reg_t bounds)
6099
{
6100
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
68✔
6101
   vcode_add_arg(op, value);
68✔
6102
   vcode_add_arg(op, context);
68✔
6103
   vcode_add_arg(op, locus);
68✔
6104
   if (bounds != VCODE_INVALID_REG)
68✔
6105
      vcode_add_arg(op, bounds);
8✔
6106

6107
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
68✔
6108
                "invalid reflect value context argument");
6109
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
68✔
6110
                "locus argument to reflect value must be a debug locus");
6111

6112
   vcode_type_t type = vtype_access(vtype_opaque());
68✔
6113
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
68✔
6114
}
6115

6116
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
68✔
6117
                                 vcode_reg_t bounds)
6118
{
6119
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
68✔
6120
   vcode_add_arg(op, context);
68✔
6121
   vcode_add_arg(op, locus);
68✔
6122
   if (bounds != VCODE_INVALID_REG)
68✔
6123
      vcode_add_arg(op, bounds);
12✔
6124

6125
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
68✔
6126
                "invalid reflect value context argument");
6127
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
68✔
6128
                "locus argument to reflect value must be a debug locus");
6129

6130
   vcode_type_t type = vtype_access(vtype_opaque());
68✔
6131
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
68✔
6132
}
6133

6134
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
352✔
6135
                                  int nargs)
6136
{
6137
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
352✔
6138
   op->func = func;
352✔
6139

6140
   for (int i = 0; i < nargs; i++)
816✔
6141
      vcode_add_arg(op, args[i]);
464✔
6142

6143
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
352✔
6144
}
6145

6146
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
45✔
6147
{
6148
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
45✔
6149
   vcode_add_arg(op, left);
45✔
6150
   vcode_add_arg(op, right);
45✔
6151

6152
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
45✔
6153
                "or trigger left argument must be trigger");
6154
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
45✔
6155
                "or trigger right argument must be trigger");
6156

6157
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
45✔
6158
}
6159

6160
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
86✔
6161
{
6162
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
86✔
6163
   vcode_add_arg(op, left);
86✔
6164
   vcode_add_arg(op, right);
86✔
6165

6166
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
86✔
6167
                "cmp trigger left argument must be signal");
6168
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
86✔
6169
                "cmp trigger right argument must be integer");
6170

6171
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
86✔
6172
}
6173

6174
void emit_add_trigger(vcode_reg_t trigger)
493✔
6175
{
6176
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
493✔
6177
   vcode_add_arg(op, trigger);
493✔
6178

6179
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
493✔
6180
                "add trigger argument must be trigger");
6181
}
493✔
6182

6183
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
239✔
6184
                               vcode_type_t type, vcode_stamp_t stamp,
6185
                               const vcode_reg_t *args, int nargs)
6186
{
6187
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
239✔
6188
   op->type  = type;
239✔
6189
   op->ident = scope;
239✔
6190
   vcode_add_arg(op, locus);
239✔
6191
   for (int i = 0; i < nargs; i++)
279✔
6192
      vcode_add_arg(op, args[i]);
40✔
6193

6194
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
239✔
6195
                "bind external argument must be locus");
6196

6197
   op->result = vcode_add_reg(vtype_pointer(type), VCODE_INVALID_STAMP);
239✔
6198
   vcode_reg_data(op->result)->stamp = stamp;
239✔
6199
   return op->result;
239✔
6200
}
6201

6202
void emit_put_driver(vcode_reg_t target, vcode_reg_t count, vcode_reg_t values)
555✔
6203
{
6204
   op_t *op = vcode_add_op(VCODE_OP_PUT_DRIVER);
555✔
6205
   vcode_add_arg(op, target);
555✔
6206
   vcode_add_arg(op, count);
555✔
6207
   vcode_add_arg(op, values);
555✔
6208

6209
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
555✔
6210
                "put driver target is not signal");
6211
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
555✔
6212
                "put driver count is not offset type");
6213
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
555✔
6214
                "signal cannot be values argument for put driver");
6215
}
555✔
6216

6217
void emit_deposit_signal(vcode_reg_t target, vcode_reg_t count,
33✔
6218
                         vcode_reg_t values)
6219
{
6220
   op_t *op = vcode_add_op(VCODE_OP_DEPOSIT_SIGNAL);
33✔
6221
   vcode_add_arg(op, target);
33✔
6222
   vcode_add_arg(op, count);
33✔
6223
   vcode_add_arg(op, values);
33✔
6224

6225
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
33✔
6226
                "deposit signal target is not signal");
6227
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
33✔
6228
                "deposit signal count is not offset type");
6229
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
33✔
6230
                "signal cannot be values argument for deposit signal");
6231
}
33✔
6232

6233
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
1,451✔
6234
{
6235
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
1,451✔
6236
   vcode_add_arg(op, spec);
1,451✔
6237
   vcode_add_arg(op, length);
1,451✔
6238
   if (locus != VCODE_INVALID_REG)
1,451✔
6239
      vcode_add_arg(op, locus);
1,233✔
6240

6241
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
1,451✔
6242
                "spec argument to bind foreign must be a pointer");
6243
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
1,451✔
6244
                "length argument to bind foreign must be offset");
6245
   VCODE_ASSERT(locus == VCODE_INVALID_REG
1,451✔
6246
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6247
                "locus argument to bind foreign value must be a debug locus");
6248
}
1,451✔
6249

6250
vcode_reg_t emit_instance_name(vcode_reg_t kind)
7,190✔
6251
{
6252
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
7,190✔
6253
   vcode_add_arg(op, kind);
7,190✔
6254

6255
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
7,190✔
6256
                "kind argument to instance name must be offset");
6257

6258
   vcode_type_t type = vtype_uarray(1, vtype_char());
7,190✔
6259
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
7,190✔
6260
}
6261

6262
vcode_reg_t emit_get_counters(ident_t block)
958✔
6263
{
6264
   op_t *op = vcode_add_op(VCODE_OP_GET_COUNTERS);
958✔
6265
   op->ident = block;
958✔
6266

6267
   vcode_type_t vint32 = vtype_int(INT32_MIN, INT32_MAX);
958✔
6268
   vcode_type_t type = vtype_pointer(vint32);
958✔
6269
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
958✔
6270
}
6271

6272
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
14,299✔
6273
{
6274
   vcode_state_t state;
14,299✔
6275
   vcode_state_save(&state);
14,299✔
6276

6277
   vcode_select_unit(vu);
14,299✔
6278

6279
   const int nblocks = vcode_count_blocks();
14,299✔
6280
   for (int i = 0; i < nblocks; i++) {
36,051✔
6281
      vcode_select_block(i);
21,752✔
6282

6283
      const int nops = vcode_count_ops();
21,752✔
6284
      for (int op = 0; op < nops; op++) {
427,407✔
6285
         switch (vcode_get_op(op)) {
405,655✔
6286
         case VCODE_OP_LINK_PACKAGE:
496✔
6287
            (*fn)(vcode_get_ident(op), ctx);
496✔
6288
            break;
496✔
6289
         case VCODE_OP_FCALL:
15,722✔
6290
         case VCODE_OP_PCALL:
6291
         case VCODE_OP_CLOSURE:
6292
         case VCODE_OP_PROTECTED_INIT:
6293
         case VCODE_OP_PACKAGE_INIT:
6294
         case VCODE_OP_FUNCTION_TRIGGER:
6295
            (*fn)(vcode_get_func(op), ctx);
15,722✔
6296
            break;
15,722✔
6297
         default:
6298
            break;
6299
         }
6300
      }
6301
   }
6302

6303
   vcode_state_restore(&state);
14,299✔
6304
}
14,299✔
6305

6306
#if VCODE_CHECK_UNIONS
6307
#define OP_USE_COUNT_U0(x)                                              \
6308
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6309
#define OP_USE_COUNT_U1(x)                                              \
6310
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6311
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6312
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6313

6314
__attribute__((constructor))
6315
static void vcode_check_unions(void)
6316
{
6317
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6318
   for (int i = 0; i < 256; i++) {
6319
      assert(OP_USE_COUNT_U0(i) <= 1);
6320
      assert(OP_USE_COUNT_U1(i) <= 1);
6321
   }
6322
}
6323
#endif  // VCODE_CHECK_UNIONS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc