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

nickg / nvc / 24799882095

22 Apr 2026 08:03PM UTC coverage: 92.296% (-0.06%) from 92.356%
24799882095

Pull #1319

github

web-flow
Merge d085ed3e9 into d88f5611a
Pull Request #1319: Partial support of PSL next_a

62 of 121 new or added lines in 10 files covered. (51.24%)

270 existing lines in 7 files now uncovered.

76808 of 83219 relevant lines covered (92.3%)

611118.33 hits per line

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

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

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

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

36
DECLARE_AND_DEFINE_ARRAY(vcode_reg);
15,873,244✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_block);
469,132✔
38
DECLARE_AND_DEFINE_ARRAY(vcode_type);
127,806✔
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,293,709✔
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,815✔
179
DECLARE_AND_DEFINE_ARRAY(var);
755,452✔
180
DECLARE_AND_DEFINE_ARRAY(reg);
13,253,643✔
181
DECLARE_AND_DEFINE_ARRAY(block);
193,701✔
182
DECLARE_AND_DEFINE_ARRAY(vtype);
34,138,920✔
183
DECLARE_AND_DEFINE_ARRAY(vstamp);
2,122,505✔
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)
56,074✔
239
{
240
   int64_t result;
56,074✔
241
   if (__builtin_add_overflow(a, b, &result))
56,074✔
242
      return b < 0 ? INT64_MIN : INT64_MAX;
14,399✔
243

244
   return result;
245
}
246

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

253
   return result;
254
}
255

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

262
   return result;
263
}
264

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

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

275
   return reg;
2,102,332✔
276
}
277

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

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

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

294
   block_t *block = vcode_block_data();
2,734,625✔
295

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

302
   return op;
2,734,625✔
303
}
304

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

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

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

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

324
static op_t *vcode_find_definition(vcode_reg_t reg)
2,866,726✔
325
{
326
   for (int i = active_block; i >= 0; i--) {
2,905,359✔
327
      block_t *b = &(active_unit->blocks.items[i]);
2,903,782✔
328
      for (int j = b->ops.count - 1; j >= 0; j--) {
59,167,039✔
329
         if (b->ops.items[j].result == reg)
59,128,406✔
330
            return &(b->ops.items[j]);
2,865,149✔
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,845,412✔
339
{
340
   op_t *defn = vcode_find_definition(reg);
2,845,412✔
341
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
2,845,412✔
342
                what, reg);
343
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
2,845,412✔
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,845,412✔
352
#endif
353

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

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

367
   int depth = MASK_CONTEXT(type);
8,399,132✔
368
   assert(depth <= unit->depth);
8,399,132✔
369
   while (depth != unit->depth)
9,624,726✔
370
      unit = unit->context;
1,225,594✔
371

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

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

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

383
   int depth = MASK_CONTEXT(stamp);
1,629,333✔
384
   assert(depth <= unit->depth);
1,629,333✔
385
   while (depth != unit->depth)
1,672,204✔
386
      unit = unit->context;
42,871✔
387

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

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

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

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

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

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

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

441
         vcode_select_unit(vu);
824✔
442

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

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

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

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

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

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

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

476
               VCODE_ASSERT(
275,341✔
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,907✔
486
         const vtype_kind_t rkind = vcode_reg_kind(reg);
5,869✔
487
         if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
5,869✔
488
            // Function may return a pointer to its argument
489
            vcode_heap_allocate(defn->args.items[i]);
5,731✔
490
         }
491
      }
492
      break;
493

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

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

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

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

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

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

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

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

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

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

574
   if (unit == active_unit)
75,556✔
575
      vcode_close();
14,361✔
576

577
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
93,635✔
578
      assert(it->context == unit);
18,079✔
579
      it->context = NULL;
18,079✔
580
   }
581
   unit->children = NULL;
75,556✔
582

583
   if (unit->context != NULL) {
75,556✔
584
      vcode_unit_t *it = &(unit->context->children);
20,790✔
585
      for (; *it != NULL && *it != unit; it = &((*it)->next))
53,646✔
586
         ;
587
      assert(*it != NULL);
20,790✔
588
      *it = (*it)->next;
20,790✔
589
   }
590

591
   for (unsigned i = 0; i < unit->blocks.count; i++) {
269,231✔
592
      block_t *b = &(unit->blocks.items[i]);
193,675✔
593

594
      for (unsigned j = 0; j < b->ops.count; j++) {
2,812,229✔
595
         op_t *o = &(b->ops.items[j]);
2,618,554✔
596
         if (OP_HAS_COMMENT(o->kind))
2,618,554✔
597
            free(o->comment);
304,537✔
598
         if (OP_HAS_TARGET(o->kind))
2,618,554✔
599
            free(o->targets.items);
110,395✔
600
         free(o->args.items);
2,618,554✔
601
      }
602
      free(b->ops.items);
193,675✔
603
   }
604
   free(unit->blocks.items);
75,556✔
605

606
   for (unsigned i = 0; i < unit->types.count; i++) {
569,674✔
607
      vtype_t *vt = &(unit->types.items[i]);
494,118✔
608
      if (vt->kind == VCODE_TYPE_RECORD)
494,118✔
609
         free(vt->fields.items);
9,002✔
610
   }
611
   free(unit->types.items);
75,556✔
612

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

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

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

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

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

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

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

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

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

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

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

663
   if (s->u.intg.low == s->u.intg.high) {
961,644✔
664
      if (value) *value = s->u.intg.low;
745,149✔
665
      return true;
745,149✔
666
   }
667
   else
668
      return false;
669
}
670

671
bool vcode_reg_bounds(vcode_reg_t reg, int64_t *low, int64_t *high)
578,504✔
672
{
673
   reg_t *r = vcode_reg_data(reg);
578,504✔
674
   if (r->stamp == VCODE_INVALID_STAMP) {
578,504✔
675
      vtype_t *t = vcode_type_data(r->type);
103,254✔
676
      if (t->kind == VCODE_TYPE_INT || t->kind == VCODE_TYPE_OFFSET) {
103,254✔
677
         *low = t->low;
101,869✔
678
         *high = t->high;
101,869✔
679
         return true;
101,869✔
680
      }
681
   }
682
   else {
683
      vstamp_t *s = vcode_stamp_data(r->stamp);
475,250✔
684
      if (s->kind == VCODE_STAMP_INT) {
475,250✔
685
         *low = s->u.intg.low;
474,710✔
686
         *high = s->u.intg.high;
474,710✔
687
         return true;
474,710✔
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)
75,582✔
718
{
719
   // Prune assignments to unused registers
720

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

723
   int pruned = 0;
75,582✔
724
   do {
107,097✔
725
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
107,097✔
726
      pruned = 0;
107,097✔
727

728
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
424,623✔
729
         block_t *b = &(active_unit->blocks.items[i]);
317,526✔
730

731
         for (int j = b->ops.count - 1; j >= 0; j--) {
5,161,558✔
732
            op_t *o = &(b->ops.items[j]);
4,844,032✔
733

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

796
            default:
797
               break;
798
            }
799

800
            for (int k = 0; k < o->args.count; k++) {
14,461,470✔
801
               if (o->args.items[k] != VCODE_INVALID_REG)
9,617,438✔
802
                  uses[o->args.items[k]]++;
9,569,836✔
803
            }
804
         }
805
      }
806
   } while (pruned > 0);
107,097✔
807

808
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
269,283✔
809
      block_t *b = &(active_unit->blocks.items[i]);
193,701✔
810
      op_t *dst = &(b->ops.items[0]);
193,701✔
811
      size_t copied = 0;
193,701✔
812
      for (int j = 0; j < b->ops.count; j++) {
2,928,326✔
813
         const op_t *src = &(b->ops.items[j]);
2,734,625✔
814
         if (src->kind != (vcode_op_t)-1) {
2,734,625✔
815
            if (src != dst) {
2,618,691✔
816
               assert(dst < src);
890,966✔
817
               *dst = *src;
890,966✔
818
            }
819
            dst++;
2,618,691✔
820
            copied++;
2,618,691✔
821
         }
822
      }
823

824
      assert(copied <= b->ops.count);
193,701✔
825
      b->ops.count = copied;
193,701✔
826
   }
827
}
75,582✔
828

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

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

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

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

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

862
   return VCODE_INVALID_VAR;
863
}
864

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1186
   return col;
1187
}
1188

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

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

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

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

1213
   printf(" => ");
1214

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2454
   active_block = old_block;
2455
}
2456
LCOV_EXCL_STOP
2457

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

2463
   switch (at->kind) {
5,783,900✔
2464
   case VCODE_TYPE_INT:
3,857,789✔
2465
      return (at->low == bt->low) && (at->high == bt->high);
5,503,747✔
2466
   case VCODE_TYPE_REAL:
76,028✔
2467
      return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
76,089✔
2468
   case VCODE_TYPE_CARRAY:
165,409✔
2469
      return at->size == bt->size && vtype_eq(at->elem, bt->elem);
177,123✔
2470
   case VCODE_TYPE_UARRAY:
119,123✔
2471
      return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
147,655✔
2472
   case VCODE_TYPE_POINTER:
715,843✔
2473
   case VCODE_TYPE_ACCESS:
2474
      return vtype_eq(at->pointed, bt->pointed);
715,843✔
2475
   case VCODE_TYPE_OFFSET:
2476
   case VCODE_TYPE_OPAQUE:
2477
   case VCODE_TYPE_DEBUG_LOCUS:
2478
   case VCODE_TYPE_TRIGGER:
2479
      return true;
2480
   case VCODE_TYPE_RESOLUTION:
129,744✔
2481
   case VCODE_TYPE_CLOSURE:
2482
   case VCODE_TYPE_SIGNAL:
2483
   case VCODE_TYPE_FILE:
2484
      return vtype_eq(at->base, bt->base);
129,744✔
2485
   case VCODE_TYPE_RECORD:
91,551✔
2486
   case VCODE_TYPE_CONTEXT:
2487
      return at->name == bt->name;
91,551✔
UNCOV
2488
   default:
×
2489
      should_not_reach_here();
2490
   }
2491
}
2492

2493
bool vtype_eq(vcode_type_t a, vcode_type_t b)
7,529,904✔
2494
{
2495
   assert(active_unit != NULL);
7,529,904✔
2496

2497
   if (a == b)
7,529,904✔
2498
      return true;
2499
   else if (MASK_CONTEXT(a) == MASK_CONTEXT(b))
1,478,523✔
2500
      return false;   // Guaranteed by vtype_new
2501
   else {
2502
      const vtype_t *at = vcode_type_data(a);
177,227✔
2503
      const vtype_t *bt = vcode_type_data(b);
177,227✔
2504

2505
      return vtype_eq_internal(at, bt);
177,227✔
2506
   }
2507
}
2508

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

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

2518
   for (int i = 0; i < index; i++) {
22,419,160✔
2519
      const vtype_t *cmp = vtype_array_nth_ptr(&(active_unit->types), i);
21,924,975✔
2520
      if (vtype_eq_internal(new, cmp)) {
21,924,975✔
2521
         active_unit->types.count--;
3,320,628✔
2522
         return MAKE_HANDLE(active_unit->depth, i);
3,320,628✔
2523
      }
2524
   }
2525

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

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

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

2538
   switch (bits_for_range(low, high)) {
2,304,387✔
2539
   case 64:
80,606✔
2540
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
80,606✔
2541
      break;
80,606✔
2542
   case 32:
508,898✔
2543
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
508,898✔
2544
      break;
508,898✔
2545
   case 16:
243✔
2546
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
243✔
2547
      break;
243✔
2548
   case 8:
1,084,123✔
2549
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
1,084,123✔
2550
      break;
1,084,123✔
2551
   case 1:
630,517✔
2552
      n->repr = VCODE_REPR_U1;
630,517✔
2553
      break;
630,517✔
UNCOV
2554
   case 0:
×
UNCOV
2555
      n->repr = VCODE_REPR_I64;    // Null range
×
UNCOV
2556
      break;
×
UNCOV
2557
   default:
×
2558
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2559
   }
2560

2561
   return vtype_new(n);
2,304,387✔
2562
}
2563

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

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

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

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

2583
   return vtype_new(n);
91,113✔
2584
}
2585

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

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

2596
   return VCODE_INVALID_TYPE;
2597
}
2598

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

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

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

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

2624
   return handle;
18,004✔
2625
}
2626

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

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

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

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

2643
   return vtype_new(n);
116,996✔
2644
}
2645

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

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

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

2657
   return vtype_new(n);
305,306✔
2658
}
2659

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

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

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

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

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

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

2681
   return vtype_new(n);
68,672✔
2682
}
2683

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

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

2692
   return vtype_new(n);
17,428✔
2693
}
2694

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

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

2703
   return vtype_new(n);
12,046✔
2704
}
2705

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

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

2715
   return vtype_new(n);
82,875✔
2716
}
2717

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

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

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

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

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

2739
   return vtype_new(n);
466,504✔
2740
}
2741

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

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

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

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

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

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

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

2769
   return vtype_new(n);
237,033✔
2770
}
2771

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2915
bool vtype_is_signal(vcode_type_t type)
214,050✔
2916
{
2917
   vtype_t *vt = vcode_type_data(type);
380,947✔
2918
   switch (vt->kind) {
380,947✔
2919
   case VCODE_TYPE_SIGNAL:
2920
      return true;
2921
   case VCODE_TYPE_POINTER:
99,247✔
2922
      return vtype_is_signal(vt->pointed);
99,247✔
2923
   case VCODE_TYPE_RECORD:
2924
      for (int i = 0; i < vt->fields.count; i++) {
49,186✔
2925
         if (vtype_is_signal(vt->fields.items[i]))
38,711✔
2926
            return true;
2927
      }
2928
      return false;
2929
   case VCODE_TYPE_UARRAY:
67,650✔
2930
   case VCODE_TYPE_CARRAY:
2931
      return vtype_is_signal(vt->elem);
67,650✔
2932
   default:
164,106✔
2933
      return false;
164,106✔
2934
   }
2935
}
2936

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

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

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

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

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

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

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

3005
   for (int i = 0; i < active_unit->stamps.count; i++) {
10,904,372✔
3006
      vstamp_t *cmp = &(active_unit->stamps.items[i]);
10,411,200✔
3007
      if (cmp->kind == s->kind && memcmp(&cmp->u, &s->u, sizeof(s->u)) == 0)
10,411,200✔
3008
         return MAKE_HANDLE(active_unit->depth, i);
617,479✔
3009
   }
3010

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

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

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

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

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

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

3049
   return active_unit->params.count;
27,931✔
3050
}
3051

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

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

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

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

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

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

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

3095
   vcode_block_t bnum = active_unit->blocks.count;
193,701✔
3096

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

3100
   if (active_block != VCODE_INVALID_BLOCK)
193,701✔
3101
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
118,119✔
3102
   else
3103
      bptr->last_loc = LOC_INVALID;
75,582✔
3104

3105
   return bnum;
193,701✔
3106
}
3107

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

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

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

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

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

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

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

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

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

3162
   active_unit->result = type;
26,916✔
3163
}
26,916✔
3164

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

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

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

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

3190
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
89,948✔
3191
{
3192
   int hops = 0;
89,948✔
3193
   for (; (unit = unit->context); hops++)
217,430✔
3194
      ;
3195
   return hops;
89,948✔
3196
}
3197

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

3202
   child->next = NULL;
38,869✔
3203
   if (context->children == NULL)
38,869✔
3204
      context->children = child;
18,292✔
3205
   else {
3206
      vcode_unit_t it;
3207
      for (it = context->children; it->next != NULL; it = it->next)
91,078✔
3208
         ;
3209
      it->next = child;
20,577✔
3210
   }
3211
}
38,869✔
3212

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

3223
   vcode_add_child(context, vu);
15,713✔
3224

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

3229
   return vu;
15,713✔
3230
}
3231

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

3242
   vcode_add_child(context, vu);
281✔
3243

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

3248
   return vu;
281✔
3249
}
3250

3251
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
10,582✔
3252
{
3253
   assert(context->kind == VCODE_UNIT_INSTANCE);
10,582✔
3254

3255
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
10,582✔
3256
   vu->kind     = VCODE_UNIT_PROCESS;
10,582✔
3257
   vu->name     = name;
10,582✔
3258
   vu->context  = context;
10,582✔
3259
   vu->depth    = vcode_unit_calc_depth(vu);
10,582✔
3260
   vu->result   = VCODE_INVALID_TYPE;
10,582✔
3261
   vu->object   = obj;
10,582✔
3262

3263
   vcode_add_child(context, vu);
10,582✔
3264

3265
   vcode_select_unit(vu);
10,582✔
3266
   vcode_select_block(emit_block());
10,582✔
3267
   emit_debug_info(&(obj->loc));
10,582✔
3268

3269
   return vu;
10,582✔
3270
}
3271

3272
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
16,870✔
3273
{
3274
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
16,870✔
3275

3276
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
16,870✔
3277
   vu->kind     = VCODE_UNIT_INSTANCE;
16,870✔
3278
   vu->name     = name;
16,870✔
3279
   vu->context  = context;
16,870✔
3280
   vu->depth    = vcode_unit_calc_depth(vu);
16,870✔
3281
   vu->result   = VCODE_INVALID_TYPE;
16,870✔
3282
   vu->object   = obj;
16,870✔
3283

3284
   if (context != NULL)
16,870✔
3285
      vcode_add_child(context, vu);
10,254✔
3286

3287
   vcode_select_unit(vu);
16,870✔
3288
   vcode_select_block(emit_block());
16,870✔
3289
   emit_debug_info(&(obj->loc));
16,870✔
3290

3291
   return vu;
16,870✔
3292
}
3293

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

3304
   if (context != NULL)
16,415✔
3305
      vcode_add_child(context, vu);
314✔
3306

3307
   vcode_select_unit(vu);
16,415✔
3308
   vcode_select_block(emit_block());
16,415✔
3309
   emit_debug_info(&(obj->loc));
16,415✔
3310

3311
   return vu;
16,415✔
3312
}
3313

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

3324
   if (context != NULL)
1,027✔
3325
      vcode_add_child(context, vu);
1,027✔
3326

3327
   vcode_select_unit(vu);
1,027✔
3328
   vcode_select_block(emit_block());
1,027✔
3329
   emit_debug_info(&(obj->loc));
1,027✔
3330

3331
   return vu;
1,027✔
3332
}
3333

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

3344
   if (context != NULL)
328✔
3345
      vcode_add_child(context, vu);
328✔
3346

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

3351
   return vu;
328✔
3352
}
3353

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

3365
   if (context != NULL)
14,366✔
3366
      vcode_add_child(context, vu);
370✔
3367

3368
   vcode_select_unit(vu);
14,366✔
3369
   vcode_select_block(emit_block());
14,366✔
3370

3371
   return vu;
14,366✔
3372
}
3373

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

3384
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
19,525✔
3385
   vcode_add_arg(op, value);
19,525✔
3386
   vcode_add_arg(op, severity);
19,525✔
3387
   vcode_add_arg(op, message);
19,525✔
3388
   vcode_add_arg(op, length);
19,525✔
3389
   vcode_add_arg(op, locus);
19,525✔
3390

3391
   if (hint_left != VCODE_INVALID_REG) {
19,525✔
3392
      vcode_add_arg(op, hint_left);
8,132✔
3393
      vcode_add_arg(op, hint_right);
8,132✔
3394

3395
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
8,132✔
3396
                   "left hint must be scalar");
3397
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
8,132✔
3398
                   "right hint must be scalar");
3399
   }
3400

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

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

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

3429
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
46,992✔
3430
{
3431
   if (lhs == rhs) {
46,992✔
3432
      if (cmp == VCODE_CMP_EQ)
525✔
3433
         return emit_const(vtype_bool(), 1);
313✔
3434
      else if (cmp == VCODE_CMP_NEQ)
212✔
UNCOV
3435
         return emit_const(vtype_bool(), 0);
×
3436
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
212✔
UNCOV
3437
         return emit_const(vtype_bool(), 1);
×
3438
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
212✔
3439
         return emit_const(vtype_bool(), 0);
212✔
3440
   }
3441

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

3462
   // Reuse any previous operation in this block with the same arguments
3463
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
906,668✔
3464
      if (other->args.count == 2 && other->args.items[0] == lhs
33,503✔
3465
          && other->args.items[1] == rhs && other->cmp == cmp)
3,006✔
3466
         return other->result;
256✔
3467
   }
3468

3469
   op_t *op = vcode_add_op(VCODE_OP_CMP);
45,779✔
3470
   vcode_add_arg(op, lhs);
45,779✔
3471
   vcode_add_arg(op, rhs);
45,779✔
3472
   op->cmp    = cmp;
45,779✔
3473
   op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP);
45,779✔
3474

3475
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
45,779✔
3476
                "arguments to cmp are not the same type");
3477

3478
   return op->result;
45,779✔
3479
}
3480

3481
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_stamp_t stamp,
45,582✔
3482
                       const vcode_reg_t *args, int nargs)
3483
{
3484
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
45,582✔
3485
   o->func = func;
45,582✔
3486
   o->type = type;
45,582✔
3487
   for (int i = 0; i < nargs; i++)
160,988✔
3488
      vcode_add_arg(o, args[i]);
115,406✔
3489

3490
   for (int i = 0; i < nargs; i++)
160,988✔
3491
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
115,406✔
3492
                   "invalid argument to function");
3493

3494
   if (type == VCODE_INVALID_TYPE)
45,582✔
3495
      return (o->result = VCODE_INVALID_REG);
7,406✔
3496
   else
3497
      return (o->result = vcode_add_reg(type, stamp));
38,176✔
3498
}
3499

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

3508
   vcode_block_array_add(&(o->targets), resume_bb);
1,155✔
3509

3510
   for (int i = 0; i < nargs; i++)
3,849✔
3511
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,694✔
3512
                   "invalid argument to procedure");
3513

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

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

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

3531
   return (op->result = vcode_add_reg(vtype_pointer(type), stamp));
10,486✔
3532
}
3533

3534
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
2,415,208✔
3535
{
3536
   // Reuse any previous constant in this block with the same type and value
3537
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
57,725,757✔
3538
      if (other->value == value && vtype_eq(type, other->type))
19,806,083✔
3539
         return other->result;
1,766,879✔
3540
   }
3541

3542
   op_t *op = vcode_add_op(VCODE_OP_CONST);
648,329✔
3543
   op->value  = value;
648,329✔
3544
   op->type   = type;
648,329✔
3545
   op->result = vcode_add_reg(type, vstamp_int(value, value));
648,329✔
3546

3547
   vtype_kind_t type_kind = vtype_kind(type);
648,329✔
3548
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
648,329✔
3549
                "constant must have integer or offset type");
3550

3551
   return op->result;
3552
}
3553

3554
vcode_reg_t emit_const_real(vcode_type_t type, double value)
89,476✔
3555
{
3556
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
2,783,816✔
3557
      if (other->real == value && other->type == type)
1,179,205✔
3558
         return other->result;
35,067✔
3559
   }
3560

3561
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
54,409✔
3562
   op->real   = value;
54,409✔
3563
   op->type   = type;
54,409✔
3564
   op->result = vcode_add_reg(op->type, vstamp_real(value, value));
54,409✔
3565

3566
   return op->result;
54,409✔
3567
}
3568

3569
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
58,174✔
3570
{
3571
   vtype_kind_t kind = vtype_kind(type);
58,174✔
3572

3573
   // Reuse any previous operation in this block with the same arguments
3574
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
3,178,093✔
3575
      if (other->args.count != num)
227,232✔
3576
         continue;
134,832✔
3577
      else if (!vtype_eq(vcode_reg_type(other->result), type))
92,400✔
3578
         continue;
3,983✔
3579

3580
      bool match = true;
3581
      for (int i = 0; match && i < num; i++) {
683,344✔
3582
         if (other->args.items[i] != values[i])
594,927✔
3583
            match = false;
78,804✔
3584
      }
3585

3586
      if (match) return other->result;
88,417✔
3587
   }
3588

3589
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
48,561✔
3590
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
48,561✔
3591

3592
   for (int i = 0; i < num; i++)
2,885,008✔
3593
      vcode_add_arg(op, values[i]);
2,836,447✔
3594

3595
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
48,561✔
3596
                "constant array must have constrained array type");
3597
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
48,561✔
3598
                vtype_size(type), num);
3599

3600
#ifdef DEBUG
3601
   vcode_type_t elem = vtype_elem(type);
48,561✔
3602
   for (int i = 0; i < num; i++) {
2,885,008✔
3603
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
2,836,447✔
3604
                   "wrong element type for item %d", i);
3605
      vcode_assert_const(values[i], "array");
2,836,447✔
3606
   }
3607
#endif
3608

3609
   return op->result;
48,561✔
3610
}
3611

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

3620
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
411✔
3621
   op->value = rep;
411✔
3622
   vcode_add_arg(op, value);
411✔
3623

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

3628
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
411✔
3629

3630
   return (op->result = vcode_add_reg(type, vcode_reg_data(value)->stamp));
411✔
3631
}
3632

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

3642
         if (same_regs)
1,465✔
3643
            return other->result;
251✔
3644
      }
3645
   }
3646

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

3651
   for (int i = 0; i < num; i++)
11,926✔
3652
      vcode_add_arg(op, values[i]);
8,554✔
3653

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

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

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

3668
   return op->result;
3,372✔
3669
}
3670

3671
vcode_reg_t emit_address_of(vcode_reg_t value)
60,610✔
3672
{
3673
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
3,295,665✔
3674
      if (other->args.items[0] == value)
228,845✔
3675
         return other->result;
9,631✔
3676
   }
3677

3678
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
50,979✔
3679
   vcode_add_arg(op, value);
50,979✔
3680

3681
   vcode_type_t vtype = vcode_reg_type(value);
50,979✔
3682

3683
   VCODE_ASSERT(vtype_is_composite(vtype),
50,979✔
3684
                "address of argument must be record or array");
3685

3686
   if (vtype_kind(vtype) == VCODE_TYPE_CARRAY) {
50,979✔
3687
      vcode_type_t elem = vtype_elem(vtype);
48,306✔
3688
      vcode_stamp_t stamp = vcode_reg_stamp(value);
48,306✔
3689
      return (op->result = vcode_add_reg(vtype_pointer(elem), stamp));
48,306✔
3690
   }
3691
   else {
3692
      vcode_stamp_t stamp = VCODE_INVALID_STAMP;
2,673✔
3693
      return (op->result = vcode_add_reg(vtype_pointer(vtype), stamp));
2,673✔
3694
   }
3695
}
3696

3697
void emit_wait(vcode_block_t target)
17,653✔
3698
{
3699
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
17,653✔
3700
   vcode_add_target(op, target);
17,653✔
3701
}
17,653✔
3702

3703
void emit_jump(vcode_block_t target)
48,880✔
3704
{
3705
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
48,880✔
3706
   vcode_add_target(op, target);
48,880✔
3707

3708
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
48,880✔
3709
}
48,880✔
3710

3711
vcode_var_t emit_var(vcode_type_t type, vcode_stamp_t stamp, ident_t name,
126,692✔
3712
                     vcode_var_flags_t flags)
3713
{
3714
   assert(active_unit != NULL);
126,692✔
3715

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

3724
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
126,692✔
3725

3726
   return var;
126,692✔
3727
}
3728

3729
vcode_reg_t emit_param(vcode_type_t type, vcode_stamp_t stamp, ident_t name)
41,815✔
3730
{
3731
   assert(active_unit != NULL);
41,815✔
3732

3733
   param_t *p = param_array_alloc(&(active_unit->params));
41,815✔
3734
   memset(p, '\0', sizeof(param_t));
41,815✔
3735
   p->type  = type;
41,815✔
3736
   p->stamp = stamp;
41,815✔
3737
   p->name  = name;
41,815✔
3738
   p->reg   = vcode_add_reg(type, stamp);
41,815✔
3739

3740
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
41,815✔
3741

3742
   return p->reg;
41,815✔
3743
}
3744

3745
vcode_reg_t emit_load(vcode_var_t var)
78,753✔
3746
{
3747
   // Try scanning backwards through the block for another load or store to
3748
   // this variable
3749
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
78,753✔
3750
   vcode_reg_t fold = VCODE_INVALID_REG;
78,753✔
3751
   VCODE_FOR_EACH_OP(other) {
1,273,506✔
3752
      switch (state) {
1,214,346✔
3753
      case EAGER:
497,466✔
3754
         if (other->kind == VCODE_OP_LOAD && other->address == var)
497,466✔
3755
            return other->result;
5,082✔
3756
         else if (other->kind == VCODE_OP_STORE && other->address == var)
492,384✔
3757
            return other->args.items[0];
14,511✔
3758
         else if (other->kind == VCODE_OP_FCALL
477,873✔
3759
                  || other->kind == VCODE_OP_PCALL
477,873✔
3760
                  || other->kind == VCODE_OP_FILE_READ
3761
                  || other->kind == VCODE_OP_FILE_OPEN
3762
                  || other->kind == VCODE_OP_STORE_INDIRECT
3763
                  || other->kind == VCODE_OP_DEALLOCATE)
3764
            state = CONSERVATIVE;   // May write to variable
13,303✔
3765
         break;
3766

3767
      case CONSERVATIVE:
673,181✔
3768
         if (other->kind == VCODE_OP_LOAD && other->address == var
673,181✔
3769
             && fold == VCODE_INVALID_REG)
5,864✔
3770
            fold = other->result;
4,665✔
3771
         else if (other->kind == VCODE_OP_STORE && other->address == var
668,516✔
3772
                  && fold == VCODE_INVALID_REG)
3,493✔
3773
            fold = other->args.items[0];
3,277✔
3774
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
665,239✔
3775
            state = UNSAFE;
3776
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
663,244✔
3777
            state = UNSAFE;   // Nested call captures variables
180✔
3778
         break;
3779

3780
      case UNSAFE:
3781
         break;
3782
      }
3783
   }
3784

3785
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
59,160✔
3786
      return fold;
3787

3788
   var_t *v = vcode_var_data(var);
51,747✔
3789

3790
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
51,747✔
3791
   op->address = var;
51,747✔
3792
   op->result  = vcode_add_reg(v->type, v->stamp);
51,747✔
3793

3794
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
51,747✔
3795

3796
   return op->result;
3797
}
3798

3799
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
134,881✔
3800
{
3801
   VCODE_FOR_EACH_OP(other) {
1,628,022✔
3802
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,539,726✔
3803
          && other->args.items[0] == reg) {
228,108✔
3804
         return other->result;
15,412✔
3805
      }
3806
      else if (other->kind == VCODE_OP_FCALL
1,524,314✔
3807
               || other->kind == VCODE_OP_PCALL
1,524,314✔
3808
               || other->kind == VCODE_OP_STORE
3809
               || other->kind == VCODE_OP_STORE_INDIRECT
3810
               || other->kind == VCODE_OP_MEMSET
3811
               || other->kind == VCODE_OP_COPY
3812
               || other->kind == VCODE_OP_FILE_READ)
3813
         break;   // May write to this pointer
3814
   }
3815

3816
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
119,469✔
3817
   vcode_add_arg(op, reg);
119,469✔
3818

3819
   vcode_type_t rtype = vcode_reg_type(reg);
119,469✔
3820

3821
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
119,469✔
3822
                "load indirect with non-pointer argument");
3823

3824
   vcode_type_t deref = vtype_pointed(rtype);
119,469✔
3825
   op->result = vcode_add_reg(deref, vcode_reg_stamp(reg));
119,469✔
3826

3827
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
119,469✔
3828

3829
   return op->result;
3830
}
3831

3832
void emit_store(vcode_reg_t reg, vcode_var_t var)
126,191✔
3833
{
3834
   // Any previous store to this variable in this block is dead
3835
   VCODE_FOR_EACH_OP(other) {
2,716,029✔
3836
      if (other->kind == VCODE_OP_STORE && other->address == var) {
2,609,751✔
3837
         other->kind = VCODE_OP_COMMENT;
384✔
3838
         other->comment =
768✔
3839
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
384✔
3840
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
384✔
3841
      }
3842
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
2,609,367✔
3843
         break;   // Needs to get variable for display
3844
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
2,600,711✔
3845
               && other->address == var)
57,552✔
3846
         break;   // Previous value may be used
3847
   }
3848

3849
   var_t *v = vcode_var_data(var);
126,191✔
3850
   reg_t *r = vcode_reg_data(reg);
126,191✔
3851

3852
   op_t *op = vcode_add_op(VCODE_OP_STORE);
126,191✔
3853
   vcode_add_arg(op, reg);
126,191✔
3854
   op->address = var;
126,191✔
3855

3856
   VCODE_ASSERT(vtype_eq(v->type, r->type),
126,191✔
3857
                "variable and stored value do not have same type");
3858
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
126,191✔
3859
}
126,191✔
3860

3861
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
23,088✔
3862
{
3863
   reg_t *p = vcode_reg_data(ptr);
23,088✔
3864
   reg_t *r = vcode_reg_data(reg);
23,088✔
3865

3866
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
23,088✔
3867
   vcode_add_arg(op, reg);
23,088✔
3868
   vcode_add_arg(op, ptr);
23,088✔
3869

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

3877
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
91,527✔
3878
                              vcode_reg_t locus)
3879
{
3880
   // Reuse any previous operation in this block with the same arguments
3881
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
2,270,014✔
3882
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
118,653✔
3883
         return other->result;
8,388✔
3884
   }
3885

3886
   op_t *op = vcode_add_op(kind);
83,139✔
3887
   vcode_add_arg(op, lhs);
83,139✔
3888
   vcode_add_arg(op, rhs);
83,139✔
3889
   if (locus != VCODE_INVALID_REG)
83,139✔
3890
      vcode_add_arg(op, locus);
9,757✔
3891

3892
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
83,139✔
3893

3894
   vcode_type_t lhs_type = vcode_reg_type(lhs);
83,139✔
3895
   vcode_type_t rhs_type = vcode_reg_type(rhs);
83,139✔
3896

3897
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
83,139✔
3898
                "arguments to %s are not the same type", vcode_op_string(kind));
3899

3900
   return op->result;
83,139✔
3901
}
3902

3903
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
71,408✔
3904
                               vcode_reg_t locus)
3905
{
3906
   int64_t lconst, rconst;
71,408✔
3907
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
71,408✔
3908
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
71,408✔
3909
   if (l_is_const && r_is_const)
71,408✔
3910
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
34,939✔
3911
   else if (r_is_const && rconst == 1)
36,469✔
3912
      return lhs;
3913
   else if (l_is_const && lconst == 1)
6,899✔
3914
      return rhs;
3915
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
6,195✔
3916
      return emit_const(vcode_reg_type(lhs), 0);
79✔
3917

3918
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
6,116✔
3919

3920
   double rl_low, rl_high, rr_low, rr_high;
6,116✔
3921
   int64_t l_low, l_high, r_low, r_high;
6,116✔
3922

3923
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
6,116✔
3924
       && vcode_reg_bounds(rhs, &r_low, &r_high)) {
5,409✔
3925
      const int64_t ll = smul64(l_low, r_low);
5,409✔
3926
      const int64_t lh = smul64(l_low, r_high);
5,409✔
3927
      const int64_t hl = smul64(l_high, r_low);
5,409✔
3928
      const int64_t hh = smul64(l_high, r_high);
5,409✔
3929

3930
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
5,409✔
3931
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
5,409✔
3932

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

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

3950
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,641✔
3951
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,761✔
3952

3953
      vstamp = vstamp_real(min, max);
707✔
3954
   }
3955

3956
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
6,116✔
3957

3958
   if (vstamp != VCODE_INVALID_TYPE)
6,116✔
3959
      vcode_reg_data(reg)->stamp = vstamp;
6,116✔
3960

3961
   return reg;
3962
}
3963

3964
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
67,097✔
3965
{
3966
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
67,097✔
3967
}
3968

3969
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
4,311✔
3970
{
3971
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
4,311✔
3972

3973
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
4,311✔
3974
                "trapping add may only be used with integer types");
3975

3976
   return result;
4,311✔
3977
}
3978

3979
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
2,478✔
3980
{
3981
   int64_t lconst, rconst;
2,478✔
3982
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
2,478✔
3983
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
2,478✔
3984
   if (l_is_const && r_is_const && rconst != 0)
2,478✔
3985
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
39✔
3986
   else if (r_is_const && rconst == 1)
2,439✔
3987
      return lhs;
3988

3989
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
2,435✔
3990

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

4003
   return reg;
4004
}
4005

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

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

4021
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
181✔
4022

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

4026
   return result;
4027
}
4028

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

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

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

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

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

4059
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
1,262✔
4060

4061
   int64_t l_low, l_high, r_low, r_high;
1,262✔
4062
   if (vcode_reg_bounds(lhs, &l_low, &l_high) && l_low >= 0
1,262✔
4063
       && vcode_reg_bounds(rhs, &r_low, &r_high) && r_low >= 0) {
757✔
4064
      reg_t *rr = vcode_reg_data(reg);
752✔
4065
      rr->stamp = vstamp_int(0, r_high - 1);
752✔
4066
   }
4067

4068
   return reg;
4069
}
4070

4071
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
67,307✔
4072
                               vcode_reg_t locus)
4073
{
4074
   int64_t lconst, rconst;
67,307✔
4075
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
67,307✔
4076
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
67,307✔
4077
   if (l_is_const && r_is_const)
67,307✔
4078
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
16,965✔
4079
   else if (r_is_const && rconst == 0)
50,342✔
4080
      return lhs;
4081
   else if (l_is_const && lconst == 0)
50,167✔
4082
      return rhs;
4083

4084
   int64_t l_low, l_high, r_low, r_high;
28,459✔
4085
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
28,459✔
4086
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
28,459✔
4087
       && vcode_reg_bounds(rhs, &r_low, &r_high))  {
28,037✔
4088

4089
      int64_t rbl = sadd64(l_low, r_low);
28,037✔
4090
      int64_t rbh = sadd64(l_high, r_high);
28,037✔
4091

4092
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
28,037✔
4093
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
14,783✔
4094
         if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
14,783✔
4095
            op = VCODE_OP_ADD;   // Cannot overflow
2,044✔
4096
            locus = VCODE_INVALID_REG;
2,044✔
4097
         }
4098
      }
4099

4100
      vstamp = vstamp_int(rbl, rbh);
28,037✔
4101
   }
4102

4103
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
28,459✔
4104

4105
   if (vstamp != VCODE_INVALID_STAMP)
28,459✔
4106
      vcode_reg_data(reg)->stamp = vstamp;
28,037✔
4107

4108
   return reg;
4109
}
4110

4111
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
58,407✔
4112
{
4113
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
58,407✔
4114
}
4115

4116
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
8,900✔
4117
{
4118
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
8,900✔
4119

4120
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
8,900✔
4121
                "trapping add may only be used with integer types");
4122

4123
   return result;
8,900✔
4124
}
4125

4126
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
62,931✔
4127
                               vcode_reg_t locus)
4128
{
4129
   int64_t lconst, rconst;
62,931✔
4130
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
62,931✔
4131
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
62,931✔
4132
   if (l_is_const && r_is_const)
62,931✔
4133
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
11,707✔
4134
   else if (r_is_const && rconst == 0)
51,224✔
4135
      return lhs;
4136
   else if (l_is_const && lconst == 0)
44,314✔
4137
      return emit_neg(rhs);
1,159✔
4138

4139
   int64_t l_low, l_high, r_low, r_high;
43,155✔
4140
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
43,155✔
4141
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
43,155✔
4142
       && vcode_reg_bounds(rhs, &r_low, &r_high))  {
42,779✔
4143

4144
      int64_t rbl = ssub64(l_low, r_high);
42,779✔
4145
      int64_t rbh = ssub64(l_high, r_low);
42,779✔
4146

4147
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
42,779✔
4148
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
40,184✔
4149
         if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
40,184✔
4150
            op = VCODE_OP_SUB;   // Cannot overflow
6,800✔
4151
            locus = VCODE_INVALID_REG;
6,800✔
4152
         }
4153
      }
4154

4155
      vstamp = vstamp_int(rbl, rbh);
42,779✔
4156
   }
4157

4158
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
43,155✔
4159

4160
   if (vstamp != VCODE_INVALID_TYPE)
43,155✔
4161
      vcode_reg_data(reg)->stamp = vstamp;
42,779✔
4162

4163
   return reg;
4164
}
4165

4166
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
53,519✔
4167
{
4168
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
53,519✔
4169
}
4170

4171
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
9,412✔
4172
{
4173
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
9,412✔
4174

4175
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
9,412✔
4176
                "trapping sub may only be used with integer types");
4177

4178
   return result;
9,412✔
4179
}
4180

4181
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
107,934✔
4182
{
4183
   switch (vtype_kind(var->type)) {
107,934✔
4184
   case VCODE_TYPE_CARRAY:
36,424✔
4185
      op->type = vtype_pointer(vtype_elem(var->type));
36,424✔
4186
      op->result = vcode_add_reg(op->type, var->stamp);
36,424✔
4187
      break;
36,424✔
4188

4189
   case VCODE_TYPE_RECORD:
8,751✔
4190
      op->type = vtype_pointer(var->type);
8,751✔
4191
      op->result = vcode_add_reg(op->type, VCODE_INVALID_STAMP);
8,751✔
4192
      break;
8,751✔
4193

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

4209
   default:
UNCOV
4210
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4211
                   istr(var->name));
4212
   }
4213
}
107,934✔
4214

4215
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
55,757✔
4216
{
4217
   // Try to find a previous index of this var by this offset
4218
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
2,536,571✔
4219
      if (other->address == var
147,119✔
4220
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
10,455✔
UNCOV
4221
              || (offset != VCODE_INVALID_REG
×
UNCOV
4222
                  && other->args.items[0] == offset)))
×
4223
         return other->result;
10,455✔
4224
   }
4225

4226
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
45,302✔
4227
   op->address = var;
45,302✔
4228

4229
   if (offset != VCODE_INVALID_REG)
45,302✔
UNCOV
4230
      vcode_add_arg(op, offset);
×
4231

4232
   vcode_calculate_var_index_type(op, vcode_var_data(var));
45,302✔
4233

4234
   if (offset != VCODE_INVALID_REG)
45,302✔
UNCOV
4235
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4236
                   "index offset r%d does not have offset type", offset);
4237

4238
   return op->result;
45,302✔
4239
}
4240

4241
vcode_reg_t emit_cast(vcode_type_t type, vcode_stamp_t stamp, vcode_reg_t reg)
351,099✔
4242
{
4243
   if (vtype_eq(vcode_reg_type(reg), type))
351,099✔
4244
      return reg;
351,099✔
4245

4246
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
111,782✔
4247
   vtype_kind_t to   = vtype_kind(type);
111,782✔
4248

4249
   const bool integral =
223,564✔
4250
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
111,782✔
4251
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
111,782✔
4252

4253
   int64_t value;
111,782✔
4254
   if (integral && vcode_reg_const(reg, &value))
111,782✔
4255
      return emit_const(type, value);
17,968✔
4256

4257
   // Try to find a previous cast of this register to this type
4258
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,903,663✔
4259
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
197,664✔
4260
         return other->result;
21,316✔
4261
   }
4262

4263
   op_t *op = vcode_add_op(VCODE_OP_CAST);
72,498✔
4264
   vcode_add_arg(op, reg);
72,498✔
4265
   op->type  = type;
72,498✔
4266

4267
   static const vcode_type_t allowed[][2] = {
72,498✔
4268
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4269
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4270
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4271
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4272
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4273
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4274
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4275
   };
4276

4277
   if (integral) {
72,498✔
4278
      vtype_t *vt = vcode_type_data(type);
71,327✔
4279
      int64_t low = vt->low, high = vt->high;
71,327✔
4280

4281
      vstamp_t *rt = vcode_stamp_data(vcode_reg_data(reg)->stamp);
71,327✔
4282
      if (rt != NULL) {
71,327✔
4283
         VCODE_ASSERT(rt->kind == VCODE_STAMP_INT, "must be integer stamp");
17,624✔
4284
         low = MAX(low, rt->u.intg.low);
17,624✔
4285
         high = MIN(high, rt->u.intg.high);
17,624✔
4286
      }
4287

4288
      vstamp_t *bt = vcode_stamp_data(stamp);
71,327✔
4289
      if (bt != NULL) {
71,327✔
4290
         VCODE_ASSERT(bt->kind == VCODE_STAMP_INT, "must be integer stamp");
30,102✔
4291
         low = MAX(low, bt->u.intg.low);
30,102✔
4292
         high = MIN(high, bt->u.intg.high);
30,102✔
4293
      }
4294

4295
      stamp = vstamp_int(low, high);
71,327✔
4296
   }
4297

4298
   op->result = vcode_add_reg(type, stamp);
72,498✔
4299

4300
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
128,129✔
4301
      if (from == allowed[i][0] && to == allowed[i][1])
128,129✔
4302
         return op->result;
4303
   }
4304

UNCOV
4305
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4306
}
4307

4308
void emit_return(vcode_reg_t reg)
81,319✔
4309
{
4310
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
81,319✔
4311
   if (reg != VCODE_INVALID_REG) {
81,319✔
4312
      vcode_add_arg(op, reg);
31,288✔
4313

4314
      const vtype_kind_t rkind = vcode_reg_kind(reg);
31,288✔
4315
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY)
31,288✔
4316
         vcode_heap_allocate(reg);
5,805✔
4317

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

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

4341
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
12,390✔
4342
   vcode_add_arg(op, nets);
12,390✔
4343
   vcode_add_arg(op, nnets);
12,390✔
4344
   vcode_add_arg(op, values);
12,390✔
4345
   vcode_add_arg(op, reject);
12,390✔
4346
   vcode_add_arg(op, after);
12,390✔
4347

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

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

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

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

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

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

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

4396
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
44,567✔
4397
{
4398
   int64_t tconst;
44,567✔
4399
   if (vcode_reg_const(test, &tconst)) {
44,567✔
4400
      emit_jump(!!tconst ? btrue : bfalse);
5,397✔
4401
      return;
2,751✔
4402
   }
4403

4404
   op_t *op = vcode_add_op(VCODE_OP_COND);
41,816✔
4405
   vcode_add_arg(op, test);
41,816✔
4406
   vcode_add_target(op, btrue);
41,816✔
4407
   vcode_add_target(op, bfalse);
41,816✔
4408

4409
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
41,816✔
4410
                "cond test is not a bool");
4411
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
41,816✔
4412
                "invalid cond targets");
4413
}
4414

4415
vcode_reg_t emit_neg(vcode_reg_t lhs)
8,750✔
4416
{
4417
   int64_t lconst;
8,750✔
4418
   if (vcode_reg_const(lhs, &lconst))
8,750✔
UNCOV
4419
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4420

4421
   op_t *op = vcode_add_op(VCODE_OP_NEG);
8,750✔
4422
   vcode_add_arg(op, lhs);
8,750✔
4423
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
8,750✔
4424

4425
   return op->result;
8,750✔
4426
}
4427

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

4434
   reg_t *lhs_r = vcode_reg_data(lhs);
594✔
4435

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

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

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

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

4452
vcode_reg_t emit_abs(vcode_reg_t lhs)
894✔
4453
{
4454
   int64_t lconst;
894✔
4455
   if (vcode_reg_const(lhs, &lconst))
894✔
4456
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4457

4458
   op_t *op = vcode_add_op(VCODE_OP_ABS);
893✔
4459
   vcode_add_arg(op, lhs);
893✔
4460
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
893✔
4461

4462
   return op->result;
893✔
4463
}
4464

4465
void emit_comment(const char *fmt, ...)
126,553✔
4466
{
4467
#ifndef NDEBUG
4468
   va_list ap;
126,553✔
4469
   va_start(ap, fmt);
126,553✔
4470

4471
   char *buf = xvasprintf(fmt, ap);
126,553✔
4472
   for (char *p = buf + strlen(buf) - 1;
126,553✔
4473
        p >= buf && isspace_iso88591(*p); p--)
126,553✔
UNCOV
4474
      *p = '\0';
×
4475

4476
   vcode_add_op(VCODE_OP_COMMENT)->comment = buf;
126,553✔
4477
   va_end(ap);
126,553✔
4478
#endif
4479
}
126,553✔
4480

4481
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
25,329✔
4482
                        vcode_reg_t rfalse)
4483
{
4484
   int64_t tconst;
25,329✔
4485
   if (vcode_reg_const(test, &tconst))
25,329✔
4486
      return !!tconst ? rtrue : rfalse;
6,517✔
4487
   else if (rtrue == rfalse)
18,812✔
4488
      return rtrue;
4489

4490
   // Find a previous identical select
4491
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
417,641✔
4492
      if (other->args.items[0] == test && other->args.items[1] == rtrue
16,174✔
4493
          && other->args.items[2] == rfalse)
837✔
4494
         return other->result;
704✔
4495
   }
4496

4497
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
17,877✔
4498
   vcode_add_arg(op, test);
17,877✔
4499
   vcode_add_arg(op, rtrue);
17,877✔
4500
   vcode_add_arg(op, rfalse);
17,877✔
4501
   op->result = vcode_add_reg(vcode_reg_type(rtrue), VCODE_INVALID_STAMP);
17,877✔
4502

4503
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
17,877✔
4504
                "select test must have bool type");
4505
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
17,877✔
4506
                "select arguments are not the same type");
4507

4508
   return op->result;
17,877✔
4509
}
4510

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

4525
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
10,109✔
4526
{
4527
   vcode_type_t vtbool = vtype_bool();
10,109✔
4528

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

4565
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
9,464✔
4566

4567
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
9,464✔
4568
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4569
                "arguments to %s are not boolean", vcode_op_string(op));
4570

4571
   return result;
4572
}
4573

4574
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
3,242✔
4575
{
4576
   return emit_logical(VCODE_OP_OR, lhs, rhs);
3,242✔
4577
}
4578

4579
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
6,563✔
4580
{
4581
   return emit_logical(VCODE_OP_AND, lhs, rhs);
6,563✔
4582
}
4583

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

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

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

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

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

4610
   op_t *op = vcode_add_op(VCODE_OP_NOT);
3,417✔
4611
   vcode_add_arg(op, arg);
3,417✔
4612

4613
   vcode_type_t vtbool = vtype_bool();
3,417✔
4614
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
3,417✔
4615
                "argument to not is not boolean");
4616

4617
   return (op->result = vcode_add_reg(vtbool, VCODE_INVALID_STAMP));
3,417✔
4618
}
4619

4620
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
62,280✔
4621
{
4622
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
2,398,328✔
4623
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
205,838✔
4624
         bool match = true;
4625
         for (int i = 0; match && i < ndims; i++) {
25,597✔
4626
            match = other->args.items[i*3 + 1] == dims[i].left
12,841✔
4627
               && other->args.items[i*3 + 2] == dims[i].right
11,640✔
4628
               && other->args.items[i*3 + 3] == dims[i].dir;
24,111✔
4629
         }
4630
         if (match)
12,756✔
4631
            return other->result;
11,185✔
4632
      }
4633
   }
4634

4635
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
51,095✔
4636
   vcode_add_arg(op, data);
51,095✔
4637
   for (int i = 0; i < ndims; i++) {
103,096✔
4638
      vcode_add_arg(op, dims[i].left);
52,001✔
4639
      vcode_add_arg(op, dims[i].right);
52,001✔
4640
      vcode_add_arg(op, dims[i].dir);
52,001✔
4641
   }
4642

4643
   vcode_type_t ptr_type = vcode_reg_type(data);
51,095✔
4644
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
51,095✔
4645
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
51,095✔
4646
                "wrapped data is not pointer or signal");
4647

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

4659
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
102,190✔
4660
      ? vtype_pointed(ptr_type) : ptr_type;
51,095✔
4661

4662
   op->result = vcode_add_reg(vtype_uarray(ndims, elem), vcode_reg_stamp(data));
51,095✔
4663

4664
   return op->result;
51,095✔
4665
}
4666

4667
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
138,258✔
4668
                                  vcode_reg_t array, unsigned dim,
4669
                                  unsigned arg_index)
4670
{
4671
   // Reuse any previous operation in this block with the same arguments
4672
   VCODE_FOR_EACH_OP(other) {
1,616,122✔
4673
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,554,780✔
4674
          && (rtype == VCODE_INVALID_TYPE
32,283✔
4675
              || vtype_eq(rtype, vcode_reg_type(other->result))))
13,947✔
4676
         return other->result;
32,283✔
4677
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,522,497✔
4678
         return other->args.items[1 + (dim * 3) + arg_index];
44,633✔
4679
   }
4680

4681
   op_t *op = vcode_add_op(o);
61,342✔
4682
   vcode_add_arg(op, array);
61,342✔
4683
   op->dim = dim;
61,342✔
4684

4685
   vcode_type_t atype = vcode_reg_type(array);
61,342✔
4686
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
61,342✔
4687
                "cannot use %s with non-uarray type", vcode_op_string(o));
4688

4689
   vtype_t *vt = vcode_type_data(atype);
61,342✔
4690
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
61,342✔
4691

4692
   if (rtype == VCODE_INVALID_TYPE)
61,342✔
4693
      rtype = vtype_offset();
39,603✔
4694

4695
   return (op->result = vcode_add_reg(rtype, VCODE_INVALID_STAMP));
61,342✔
4696
}
4697

4698
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
51,032✔
4699
{
4700
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
51,032✔
4701
                         array, dim, 0);
4702
}
4703

4704
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
36,524✔
4705
{
4706
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
36,524✔
4707
                         array, dim, 1);
4708
}
4709

4710
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
50,702✔
4711
{
4712
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
50,702✔
4713
                         array, dim, 2);
4714
}
4715

4716
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
61,629✔
4717
{
4718
   VCODE_FOR_EACH_OP(other) {
1,030,384✔
4719
      if (other->kind == VCODE_OP_UARRAY_LEN) {
1,000,856✔
4720
         if (other->args.items[0] == array && other->dim == dim)
64,096✔
4721
            return other->result;
12,599✔
4722
      }
4723
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
936,760✔
4724
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
19,502✔
4725
                      "array dimension %d out of bounds", dim);
4726

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

4734
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
29,528✔
4735
   vcode_add_arg(op, array);
29,528✔
4736
   op->dim = dim;
29,528✔
4737

4738
   vcode_type_t atype = vcode_reg_type(array);
29,528✔
4739
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
29,528✔
4740
                "cannot use uarray len with non-uarray type");
4741

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

4745
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
29,528✔
4746

4747
   return op->result;
29,528✔
4748
}
4749

4750
vcode_reg_t emit_unwrap(vcode_reg_t array)
47,941✔
4751
{
4752
   VCODE_FOR_EACH_OP(other) {
2,433,726✔
4753
      if (other->kind == VCODE_OP_WRAP && other->result == array)
2,399,039✔
4754
         return other->args.items[0];
10,938✔
4755
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
2,388,101✔
4756
         return other->result;
2,316✔
4757
   }
4758

4759
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
34,687✔
4760
   vcode_add_arg(op, array);
34,687✔
4761

4762
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
34,687✔
4763
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
34,687✔
4764
                "unwrap can only only be used with uarray types");
4765

4766
   vcode_type_t elem = vt->elem;
34,687✔
4767

4768
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
34,687✔
4769
      ? elem : vtype_pointer(elem);
34,687✔
4770

4771
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
34,687✔
4772
}
4773

4774
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
50,173✔
4775
                            vcode_reg_t dir)
4776
{
4777
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
2,688,733✔
UNCOV
4778
      if (other->args.items[0] == left
×
UNCOV
4779
          && other->args.items[1] == right
×
UNCOV
4780
          && other->args.items[2] == dir)
×
UNCOV
4781
         return other->result;
×
4782
   }
4783

4784
   int64_t dir_const, l_low, l_high, r_low, r_high;
50,173✔
4785
   if (vcode_reg_const(dir, &dir_const)
50,173✔
4786
       && vcode_reg_bounds(left, &l_low, &l_high)
46,036✔
4787
       && vcode_reg_bounds(right, &r_low, &r_high)) {
46,036✔
4788

4789
      if (dir_const == RANGE_TO && l_low > r_high)
46,036✔
4790
         return emit_const(vtype_bool(), 1);
84✔
4791
      else if (dir_const == RANGE_TO && l_high <= r_low)
45,952✔
4792
         return emit_const(vtype_bool(), 0);
34,890✔
4793
      else if (dir_const == RANGE_DOWNTO && r_low > l_high)
11,062✔
4794
         return emit_const(vtype_bool(), 1);
1,068✔
4795
      else if (dir_const == RANGE_DOWNTO && r_high <= l_low)
9,994✔
4796
         return emit_const(vtype_bool(), 0);
2,662✔
4797
      else if (dir_const == RANGE_TO)
7,332✔
4798
         return emit_cmp(VCODE_CMP_GT, left, right);
3,903✔
4799
      else
4800
         return emit_cmp(VCODE_CMP_GT, right, left);
3,429✔
4801
   }
4802

4803
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
4,137✔
4804
   vcode_add_arg(op, left);
4,137✔
4805
   vcode_add_arg(op, right);
4,137✔
4806
   vcode_add_arg(op, dir);
4,137✔
4807

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

4813
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
4,137✔
4814
}
4815

4816
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
19,552✔
4817
                              vcode_reg_t dir)
4818
{
4819
   vcode_reg_t left_array = VCODE_INVALID_REG,
19,552✔
4820
      right_array = VCODE_INVALID_REG,
19,552✔
4821
      dir_array = VCODE_INVALID_REG;
19,552✔
4822
   int left_dim = -1, right_dim = -1, dir_dim = -1;
19,552✔
4823

4824
   VCODE_FOR_EACH_OP(other) {
388,582✔
4825
      if (other->kind == VCODE_OP_RANGE_LENGTH
376,091✔
4826
          && other->args.items[0] == left
9,548✔
4827
          && other->args.items[1] == right
7,494✔
4828
          && other->args.items[2] == dir)
7,061✔
4829
         return other->result;
7,061✔
4830
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
369,030✔
4831
         left_array = other->args.items[0];
509✔
4832
         left_dim = other->dim;
509✔
4833
      }
4834
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
368,521✔
4835
         right_array = other->args.items[0];
509✔
4836
         right_dim = other->dim;
509✔
4837
      }
4838
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
368,012✔
4839
         dir_array = other->args.items[0];
974✔
4840
         dir_dim = other->dim;
974✔
4841
      }
4842
   }
4843

4844
   if (left_array != VCODE_INVALID_REG && left_array == right_array
12,491✔
4845
       && right_array == dir_array && left_dim == right_dim
509✔
4846
       && right_dim == dir_dim)
509✔
4847
      return emit_uarray_len(left_array, left_dim);
509✔
4848

4849
   int64_t lconst, rconst, dconst;
11,982✔
4850
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
11,982✔
4851
       && vcode_reg_const(right, &rconst)) {
6,583✔
4852

4853
      int64_t diff;
2,691✔
4854
      if (dconst == RANGE_TO)
2,691✔
4855
         diff = rconst - lconst;
2,304✔
4856
      else
4857
         diff = lconst - rconst;
387✔
4858

4859
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
2,691✔
4860
   }
4861

4862
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
9,291✔
4863
   vcode_add_arg(op, left);
9,291✔
4864
   vcode_add_arg(op, right);
9,291✔
4865
   vcode_add_arg(op, dir);
9,291✔
4866

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

4872
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
9,291✔
4873

4874
   return op->result;
9,291✔
4875
}
4876

4877
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
79,910✔
4878
{
4879
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
729,468✔
4880
      if (other->hops == hops && other->address == var)
102,453✔
4881
         return other->result;
17,278✔
4882
   }
4883

4884
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
62,632✔
4885
   op->hops    = hops;
62,632✔
4886
   op->address = var;
62,632✔
4887

4888
   VCODE_ASSERT(hops > 0, "invalid hop count");
62,632✔
4889

4890
   vcode_unit_t vu = active_unit;
62,632✔
4891
   for (int i = 0; i < hops; i++) {
138,599✔
4892
      vu = vu->context;
75,967✔
4893
      VCODE_ASSERT(vu, "hop count is greater than depth");
75,967✔
4894
   }
4895

4896
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
62,632✔
4897

4898
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
62,632✔
4899

4900
   return op->result;
62,632✔
4901
}
4902

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

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

4928
   vcode_type_t stype = vtype_signal(type);
28,332✔
4929
   return (op->result = vcode_add_reg(stype, VCODE_INVALID_STAMP));
28,332✔
4930
}
4931

4932
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
6,498✔
4933
{
4934
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
6,498✔
4935
   vcode_add_arg(op, signal);
6,498✔
4936
   vcode_add_arg(op, resolution);
6,498✔
4937

4938
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
6,498✔
4939
                "signal argument has wrong type");
4940

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

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

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

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

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

4976
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
10,363✔
4977
{
4978
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
127,289✔
4979
      if (other->args.items[0] == target && other->args.items[1] == count)
17,063✔
4980
         return;
4981
   }
4982

4983
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
10,359✔
4984
   vcode_add_arg(op, target);
10,359✔
4985
   vcode_add_arg(op, count);
10,359✔
4986

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

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

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

5012
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
11,302✔
5013
                                    vcode_reg_t nlits)
5014
{
5015
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
174,159✔
5016
      if (other->args.items[0] == closure && other->args.items[1] == nlits)
23,413✔
UNCOV
5017
         return other->result;
×
5018
   }
5019

5020
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
11,302✔
5021
                "first argument to resolution wrapper must be closure");
5022

5023
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
11,302✔
5024
   vcode_add_arg(op, closure);
11,302✔
5025
   vcode_add_arg(op, nlits);
11,302✔
5026

5027
   return (op->result = vcode_add_reg(vtype_resolution(type),
11,302✔
5028
                                      VCODE_INVALID_STAMP));
5029
}
5030

5031
vcode_reg_t emit_closure(ident_t func, vcode_type_t rtype,
12,046✔
5032
                         const vcode_reg_t *args, int nargs)
5033
{
5034
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
181,528✔
5035
      if (other->func != func || other->args.count != nargs)
23,800✔
5036
         continue;
23,800✔
5037

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

UNCOV
5042
      if (match)
×
UNCOV
5043
         return other->result;
×
5044
   }
5045

5046
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
12,046✔
5047
   op->func = func;
12,046✔
5048
   for (int i = 0; i < nargs; i++)
24,868✔
5049
      vcode_add_arg(op, args[i]);
12,822✔
5050

5051
   return (op->result = vcode_add_reg(vtype_closure(rtype),
12,046✔
5052
                                      VCODE_INVALID_STAMP));
5053
}
5054

5055
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
62,286✔
5056
{
5057
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
126,299✔
5058
      if (other->func == name)
52,550✔
5059
         return other->result;
24,592✔
5060
   }
5061

5062
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
37,694✔
5063
   op->func = name;
37,694✔
5064
   if (context != VCODE_INVALID_REG)
37,694✔
5065
      vcode_add_arg(op, context);
315✔
5066

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

5076
   return (op->result = vcode_add_reg(vtype_context(name),
37,694✔
5077
                                      VCODE_INVALID_STAMP));
5078
}
5079

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

5087
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
1,048✔
5088
      vcode_add_arg(op, path_name);
822✔
5089
      vcode_add_arg(op, inst_name);
822✔
5090

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

5097
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
1,048✔
5098
                "protected init type must be context");
5099
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
1,048✔
5100
                "invalid protected init context argument");
5101

5102
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
1,048✔
5103
}
5104

5105
void emit_process_init(vcode_reg_t closure, vcode_reg_t locus)
744✔
5106
{
5107
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
744✔
5108
   vcode_add_arg(op, closure);
744✔
5109
   vcode_add_arg(op, locus);
744✔
5110

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

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

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

5126
vcode_reg_t emit_context_upref(int hops)
30,943✔
5127
{
5128
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
226,256✔
5129
      if (other->hops == hops)
15,092✔
5130
         return other->result;
15,023✔
5131
   }
5132

5133
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
15,920✔
5134
   op->hops = hops;
15,920✔
5135

5136
   VCODE_ASSERT(hops >= 0, "invalid hop count");
15,920✔
5137

5138
   vcode_unit_t vu = active_unit;
15,920✔
5139
   for (int i = 0; i < hops; i++) {
26,481✔
5140
      vu = vu->context;
10,561✔
5141
      VCODE_ASSERT(vu, "hop count is greater than depth");
10,561✔
5142
   }
5143

5144
   return (op->result = vcode_add_reg(vtype_context(vu->name),
15,920✔
5145
                                      VCODE_INVALID_STAMP));
5146
}
5147

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

5155
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
951✔
5156
                "argument to %s is not a signal", vcode_op_string(opkind));
5157

5158
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
951✔
5159
}
5160

5161
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
630✔
5162
{
5163
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
630✔
5164
}
5165

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

5171
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
58,403✔
5172
{
5173
   // Try scanning backwards through the block for another record ref
5174
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
4,501,529✔
5175
      if (other->args.items[0] == record && other->field == field)
813,094✔
5176
         return other->result;
6,742✔
5177
   }
5178

5179
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
51,661✔
5180
   op->field = field;
51,661✔
5181
   vcode_add_arg(op, record);
51,661✔
5182

5183
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
51,661✔
5184

5185
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
51,661✔
5186
                "argument to record ref must be a pointer");
5187

5188
   vtype_t *rtype = vcode_type_data(rptype->pointed);
51,661✔
5189
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
51,661✔
5190
                "argument must be pointer to record or record signal");
5191

5192
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
51,661✔
5193

5194
   vcode_type_t field_type  = rtype->fields.items[field];
51,661✔
5195
   vcode_type_t result_type = field_type;
51,661✔
5196

5197
   const vtype_kind_t fkind = vtype_kind(field_type);
51,661✔
5198
   if (fkind == VCODE_TYPE_CARRAY)
51,661✔
5199
      result_type = vtype_elem(field_type);
7,223✔
5200
   else if (fkind == VCODE_TYPE_UARRAY)
5201
      result_type = field_type;
5202

5203
   op->result = vcode_add_reg(vtype_pointer(result_type), VCODE_INVALID_STAMP);
51,661✔
5204

5205
   return op->result;
51,661✔
5206
}
5207

5208
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
47,249✔
5209
{
5210
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
2,610,738✔
5211
      if (other->args.items[0] == array && other->args.items[1] == offset)
170,904✔
5212
         return other->result;
1,583✔
5213
   }
5214

5215
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
45,666✔
5216
   vcode_add_arg(op, array);
45,666✔
5217
   vcode_add_arg(op, offset);
45,666✔
5218

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

5227
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
45,666✔
5228
}
5229

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

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

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

5247
   op_t *op = vcode_add_op(VCODE_OP_TABLE_REF);
849✔
5248
   vcode_add_arg(op, array);
849✔
5249
   vcode_add_arg(op, stride);
849✔
5250
   for (int i = 0; i < nargs; i++)
2,063✔
5251
      vcode_add_arg(op, args[i]);
1,214✔
5252

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

5260
   for (int i = 0; i < nargs; i++)
2,063✔
5261
      VCODE_ASSERT(vtype_is_integral(vcode_reg_type(args[i])),
1,214✔
5262
                   "table ref indices must be integral");
5263

5264
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
849✔
5265
}
5266

5267
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
49,763✔
5268
{
5269
   int64_t cconst;
49,763✔
5270
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
49,763✔
5271
       && cconst == 0)
35,998✔
5272
      return;
7,501✔
5273
   else if (dest == src)
48,506✔
5274
      return;
5275

5276
   op_t *op = vcode_add_op(VCODE_OP_COPY);
42,262✔
5277
   vcode_add_arg(op, dest);
42,262✔
5278
   vcode_add_arg(op, src);
42,262✔
5279
   if (count != VCODE_INVALID_REG)
42,262✔
5280
      vcode_add_arg(op, count);
39,828✔
5281

5282
   vcode_type_t dtype = vcode_reg_type(dest);
42,262✔
5283
   vcode_type_t stype = vcode_reg_type(src);
42,262✔
5284

5285
   vtype_kind_t dkind = vtype_kind(dtype);
42,262✔
5286
   vtype_kind_t skind = vtype_kind(stype);
42,262✔
5287

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

5298
   op->type = vtype_pointed(dtype);
42,262✔
5299
}
5300

5301
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
6,087✔
5302
{
5303
   VCODE_FOR_EACH_OP(other) {
85,307✔
5304
      if (other->kind == VCODE_OP_CLEAR_EVENT)
79,308✔
5305
         break;
5306
      else if (other->kind == VCODE_OP_SCHED_EVENT
79,244✔
5307
               && other->args.items[0] == nets
3,778✔
5308
               && other->args.items[1] == n_elems)
28✔
5309
         return;
5310
   }
5311

5312
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
6,063✔
5313
   vcode_add_arg(op, nets);
6,063✔
5314
   vcode_add_arg(op, n_elems);
6,063✔
5315

5316
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
6,063✔
5317
                "nets argument to sched event must be signal");
5318
}
5319

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

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

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

5339
void emit_sched_active(vcode_reg_t nets, vcode_reg_t n_elems)
533✔
5340
{
5341
   op_t *op = vcode_add_op(VCODE_OP_SCHED_ACTIVE);
533✔
5342
   vcode_add_arg(op, nets);
533✔
5343
   vcode_add_arg(op, n_elems);
533✔
5344

5345
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
533✔
5346
                "nets argument to sched active must be signal");
5347
}
533✔
5348

5349
void emit_sched_process(vcode_reg_t delay)
7,093✔
5350
{
5351
   op_t *op = vcode_add_op(VCODE_OP_SCHED_PROCESS);
7,093✔
5352
   vcode_add_arg(op, delay);
7,093✔
5353

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

5361
void emit_resume(ident_t func)
1,155✔
5362
{
5363
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
1,155✔
5364
   op->func = func;
1,155✔
5365

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

5370
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
7,410✔
5371
{
5372
   int64_t lconst;
7,410✔
5373
   if (vcode_reg_const(len, &lconst) && lconst == 0)
7,410✔
5374
      return;
41✔
5375

5376
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
7,369✔
5377
   vcode_add_arg(op, ptr);
7,369✔
5378
   vcode_add_arg(op, value);
7,369✔
5379
   vcode_add_arg(op, len);
7,369✔
5380

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

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

5395
   for (int i = 0; i < ncases; i++) {
4,995✔
5396
      bool can_fold = false;
4,104✔
5397
      if (cases[i] == value)
4,104✔
5398
         can_fold = true;
5399
      else if (is_const && vcode_reg_const(cases[i], &cval2))
4,104✔
5400
         can_fold = (cval1 == cval2);
×
5401

UNCOV
5402
      if (can_fold) {
×
UNCOV
5403
         emit_jump(blocks[i]);
×
UNCOV
5404
         return;
×
5405
      }
5406
   }
5407

5408
   if (is_const) {
891✔
UNCOV
5409
      emit_jump(def);
×
UNCOV
5410
      return;
×
5411
   }
5412

5413
   op_t *op = vcode_add_op(VCODE_OP_CASE);
891✔
5414
   vcode_add_arg(op, value);
891✔
5415
   vcode_add_target(op, def);
891✔
5416

5417
   for (int i = 0; i < ncases; i++) {
4,995✔
5418
      vcode_add_arg(op, cases[i]);
4,104✔
5419
      vcode_add_target(op, blocks[i]);
4,104✔
5420

5421
#ifdef DEBUG
5422
      for (int j = 0; j < i; j++)
20,096✔
5423
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
15,992✔
5424
#endif
5425
   }
5426
}
5427

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

5439
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
2,121✔
5440
                "file open first argument must have file pointer type");
5441
}
2,121✔
5442

5443
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
363✔
5444
{
5445
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
363✔
5446
   vcode_add_arg(op, file);
363✔
5447
   vcode_add_arg(op, value);
363✔
5448
   if (length != VCODE_INVALID_REG)
363✔
5449
      vcode_add_arg(op, length);
287✔
5450

5451
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
363✔
5452
                "file write first argument must have file pointer type");
5453
}
363✔
5454

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

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

5476
vcode_reg_t emit_null(vcode_type_t type)
19,021✔
5477
{
5478
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
392,316✔
5479
      if (vtype_eq(vcode_reg_type(other->result), type))
11,328✔
5480
         return other->result;
5,772✔
5481
   }
5482

5483
   op_t *op = vcode_add_op(VCODE_OP_NULL);
13,249✔
5484
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
13,249✔
5485

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

5491
   return op->result;
5492
}
5493

5494
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
881✔
5495
{
5496
   op_t *op = vcode_add_op(VCODE_OP_NEW);
881✔
5497
   if (length != VCODE_INVALID_REG)
881✔
5498
      vcode_add_arg(op, length);
763✔
5499

5500
   op->result = vcode_add_reg(vtype_access(type), VCODE_INVALID_STAMP);
881✔
5501

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

5511
   return op->result;
881✔
5512
}
5513

5514
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
4,042✔
5515
{
5516
   VCODE_FOR_EACH_OP(other) {
167,022✔
5517
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
164,020✔
5518
         return;
5519
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
163,421✔
5520
         return;
5521
   }
5522

5523
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
3,002✔
5524
   vcode_add_arg(op, ptr);
3,002✔
5525
   vcode_add_arg(op, locus);
3,002✔
5526

5527
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
3,002✔
5528
                "null check argument must be an access");
5529
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
3,002✔
5530
                "locus argument to null check must be a debug locus");
5531
}
5532

5533
void emit_deallocate(vcode_reg_t ptr)
469✔
5534
{
5535
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
469✔
5536
   vcode_add_arg(op, ptr);
469✔
5537

5538
   vcode_type_t ptype = vcode_reg_type(ptr);
469✔
5539
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
469✔
5540
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5541
                "deallocate argument must be pointer to access");
5542
}
469✔
5543

5544
vcode_reg_t emit_all(vcode_reg_t reg)
4,923✔
5545
{
5546
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
235,476✔
5547
      if (other->args.items[0] == reg)
14,261✔
5548
         return other->result;
1,040✔
5549
   }
5550

5551
   op_t *op = vcode_add_op(VCODE_OP_ALL);
3,883✔
5552
   vcode_add_arg(op, reg);
3,883✔
5553

5554
   vcode_type_t vtype = vcode_reg_type(reg);
3,883✔
5555

5556
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
3,883✔
5557
                "all argument must be an access");
5558

5559
   vcode_type_t pointed = vtype_pointed(vtype);
3,883✔
5560
   op->result = vcode_add_reg(vtype_pointer(pointed), vcode_reg_stamp(reg));
3,883✔
5561

5562
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
3,883✔
5563
                "cannot dereference opaque type");
5564

5565
   return op->result;
5566
}
5567

5568
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
18,241✔
5569
{
5570
   block_t *b = &(active_unit->blocks.items[active_block]);
18,241✔
5571
   for (int i = b->ops.count - 1; i >= 0; i--) {
434,182✔
5572
      const op_t *other = &(b->ops.items[i]);
416,688✔
5573
      if (other->kind == kind && other->args.items[0] == sig)
416,688✔
5574
         return other->result;
747✔
5575
   }
5576

5577
   op_t *op = vcode_add_op(kind);
17,494✔
5578
   vcode_add_arg(op, sig);
17,494✔
5579

5580
   vcode_type_t stype = vcode_reg_type(sig);
17,494✔
5581
   op->type = stype;
17,494✔
5582

5583
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
17,494✔
5584
                "argument r%d to resolved is not a signal", sig);
5585

5586
   vcode_type_t rtype = vtype_base(stype);
17,494✔
5587

5588
   const vtype_kind_t rkind = vtype_kind(rtype);
17,494✔
5589
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
17,494✔
UNCOV
5590
      rtype = vtype_elem(rtype);
×
5591

5592
   VCODE_ASSERT(vtype_is_scalar(rtype),
17,494✔
5593
                "resolved signal base type must be scalar");
5594

5595
   op->result = vcode_add_reg(vtype_pointer(rtype), vcode_reg_stamp(sig));
17,494✔
5596

5597
   return op->result;
17,494✔
5598
}
5599

5600
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
17,988✔
5601
{
5602
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
17,988✔
5603
}
5604

5605
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
253✔
5606
{
5607
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
253✔
5608
}
5609

5610
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
56✔
5611
{
5612
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
56✔
5613
   vcode_add_arg(op, signal);
56✔
5614
   if (len != VCODE_INVALID_REG)
56✔
5615
      vcode_add_arg(op, len);
12✔
5616

5617
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
56✔
5618
                "signal argument to last event must have signal type");
5619
   VCODE_ASSERT(len == VCODE_INVALID_REG
56✔
5620
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5621
                "length argument to last event must have offset type");
5622

5623
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
56✔
5624
}
5625

5626
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
60✔
5627
{
5628
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
60✔
5629
   vcode_add_arg(op, signal);
60✔
5630
   if (len != VCODE_INVALID_REG)
60✔
5631
      vcode_add_arg(op, len);
8✔
5632

5633
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
60✔
5634
                "signal argument to last active must have signal type");
5635
   VCODE_ASSERT(len == VCODE_INVALID_REG
60✔
5636
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5637
                "length argument to last active must have offset type");
5638

5639
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
60✔
5640
}
5641

5642
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
7,400✔
5643
{
5644
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
7,400✔
5645
   vcode_add_arg(op, signal);
7,400✔
5646
   vcode_add_arg(op, locus);
7,400✔
5647

5648
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
7,400✔
5649
                "signal argument must have signal type");
5650
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
7,400✔
5651
                "locus argument must have debug locus type");
5652
}
7,400✔
5653

5654
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
48✔
5655
{
5656
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
48✔
5657
   vcode_add_arg(op, signal);
48✔
5658
   vcode_add_arg(op, len);
48✔
5659

5660
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
48✔
5661
                "signal argument to last active must have signal type");
5662
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
48✔
5663
                "length argument to last active must have offset type");
5664

5665
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
48✔
5666
}
5667

5668
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
436✔
5669
{
5670
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
436✔
5671
   vcode_add_arg(op, signal);
436✔
5672
   vcode_add_arg(op, len);
436✔
5673

5674
   vcode_type_t signal_type = vcode_reg_type(signal);
436✔
5675

5676
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
436✔
5677
                "signal argument to driving value must have signal type");
5678
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
436✔
5679
                "length argument to driving value must have offset type");
5680

5681
   vcode_type_t base_type = vtype_base(signal_type);
436✔
5682
   op->result = vcode_add_reg(vtype_pointer(base_type), VCODE_INVALID_STAMP);
436✔
5683

5684
   return op->result;
436✔
5685
}
5686

5687
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
55,819✔
5688
                       vcode_reg_t dim)
5689
{
5690
   if (rlen == llen)
55,819✔
5691
      return;
5692

5693
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
281,994✔
5694
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
3,932✔
5695
         return;
5696
   }
5697

5698
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
9,592✔
5699
   vcode_add_arg(op, llen);
9,592✔
5700
   vcode_add_arg(op, rlen);
9,592✔
5701
   vcode_add_arg(op, locus);
9,592✔
5702
   if (dim != VCODE_INVALID_REG)
9,592✔
5703
      vcode_add_arg(op, dim);
36✔
5704

5705
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
9,592✔
5706
                "locus argument to length check must be a debug locus");
5707
}
5708

5709
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
233✔
5710
{
5711
   int64_t cval;
233✔
5712
   if (vcode_reg_const(exp, &cval) && cval >= 0)
233✔
5713
      return;
73✔
5714

5715
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
2,119✔
5716
      if (other->args.items[0] == exp)
20✔
5717
         return;
5718
   }
5719

5720
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
160✔
5721
   vcode_add_arg(op, exp);
160✔
5722
   vcode_add_arg(op, locus);
160✔
5723

5724
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
160✔
5725
                "exp argument to exponent check must be a integer");
5726
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
160✔
5727
                "locus argument to exponent check must be a debug locus");
5728
}
5729

5730
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
3,565✔
5731
{
5732
   int64_t cval;
3,565✔
5733
   if (vcode_reg_const(denom, &cval) && cval != 0)
3,565✔
5734
      return;
3,450✔
5735

5736
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
3,054✔
5737
      if (other->args.items[0] == denom)
64✔
5738
         return;
5739
   }
5740

5741
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
115✔
5742
   vcode_add_arg(op, denom);
115✔
5743
   vcode_add_arg(op, locus);
115✔
5744

5745
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
115✔
5746
                "denom argument to zero check must be a integer");
5747
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
115✔
5748
                "locus argument to zero check must be a debug locus");
5749
}
5750

5751
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
135,038✔
5752
                                   vcode_reg_t right, vcode_reg_t dir)
5753
{
5754
   int64_t dconst;
135,038✔
5755
   if (!vcode_reg_const(dir, &dconst))
135,038✔
5756
      return false;
5757

5758
   int64_t lconst, rconst;
121,700✔
5759
   if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
121,700✔
5760
      const bool is_null = (dconst == RANGE_TO && lconst > rconst)
88,720✔
5761
         || (dconst == RANGE_DOWNTO && rconst > lconst);
181,747✔
5762

5763
      int64_t low, high;
93,028✔
5764
      if (vcode_reg_bounds(reg, &low, &high)) {
93,028✔
5765
         const bool ok_static =
186,056✔
5766
            (dconst == RANGE_TO && low >= lconst && high <= rconst)
88,720✔
5767
            || (dconst == RANGE_DOWNTO && low >= rconst && high <= lconst)
11,814✔
5768
            || (!is_null && (reg == left || reg == right));
100,968✔
5769

5770
         return ok_static;
93,028✔
5771
      }
5772
   }
5773
   else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
28,672✔
5774
      vstamp_t *lbounds = vcode_stamp_data(vcode_reg_data(left)->stamp);
25,846✔
5775
      vstamp_t *rbounds = vcode_stamp_data(vcode_reg_data(right)->stamp);
25,846✔
5776

5777
      assert(lbounds->kind == VCODE_STAMP_REAL);
25,846✔
5778
      assert(rbounds->kind == VCODE_STAMP_REAL);
25,846✔
5779

5780
      double low, high;
25,846✔
5781

5782
      reg_t *rr = vcode_reg_data(reg);
25,846✔
5783
      vstamp_t *bounds = vcode_stamp_data(rr->stamp);
25,846✔
5784
      if (bounds != NULL) {
25,846✔
5785
         assert(bounds->kind == VCODE_STAMP_REAL);
17,000✔
5786
         low = bounds->u.real.low;
17,000✔
5787
         high = bounds->u.real.high;
17,000✔
5788
      }
5789
      else {
5790
         vtype_t *type = vcode_type_data(rr->type);
8,846✔
5791
         assert(type->kind == VCODE_TYPE_REAL);
8,846✔
5792
         low = type->rlow;
8,846✔
5793
         high = type->rhigh;
8,846✔
5794
      }
5795

5796
      if (isfinite(low) && lbounds->u.real.low == -DBL_MAX
25,846✔
5797
          && isfinite(high) && rbounds->u.real.high == DBL_MAX) {
24,896✔
5798
         // Covers the complete double range so can never overflow
5799
         return true;
24,896✔
5800
      }
5801
   }
5802

5803
   return false;
5804
}
5805

5806
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
136,243✔
5807
                              vcode_reg_t left, vcode_reg_t right,
5808
                              vcode_reg_t dir, vcode_reg_t locus,
5809
                              vcode_reg_t hint)
5810
{
5811
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
6,602,032✔
5812
      if (other->args.items[0] == reg && other->args.items[1] == left
26,002✔
5813
          && other->args.items[2] == right && other->args.items[3] == dir)
1,436✔
5814
         return;
5815
   }
5816

5817
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
135,038✔
5818
      emit_comment("Elided bounds check for r%d", reg);
109,984✔
5819
      return;
109,984✔
5820
   }
5821

5822
   op_t *op = vcode_add_op(kind);
25,054✔
5823
   vcode_add_arg(op, reg);
25,054✔
5824
   vcode_add_arg(op, left);
25,054✔
5825
   vcode_add_arg(op, right);
25,054✔
5826
   vcode_add_arg(op, dir);
25,054✔
5827
   vcode_add_arg(op, locus);
25,054✔
5828
   vcode_add_arg(op, hint);
25,054✔
5829

5830
   VCODE_ASSERT(vtype_is_numeric(vcode_reg_type(reg)),
25,054✔
5831
                "argument to bounds check must be numeric");
5832
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
25,054✔
5833
                "locus argument to bounds check must be a debug locus");
5834
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
25,054✔
5835
                "hint argument to bounds check must be a debug locus");
5836
}
5837

5838
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
30,375✔
5839
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5840
{
5841
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
30,375✔
5842
}
30,375✔
5843

5844
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
105,868✔
5845
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5846
{
5847
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
105,868✔
5848
}
105,868✔
5849

5850
void emit_dir_check(vcode_reg_t reg, vcode_reg_t dir, vcode_reg_t locus)
4,483✔
5851
{
5852
   if (reg == dir)
4,483✔
5853
      return;
5854

5855
   op_t *op = vcode_add_op(VCODE_OP_DIR_CHECK);
3,243✔
5856
   vcode_add_arg(op, reg);
3,243✔
5857
   vcode_add_arg(op, dir);
3,243✔
5858
   vcode_add_arg(op, locus);
3,243✔
5859

5860
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
3,243✔
5861
                "locus argument to dir check must be a debug locus");
5862
}
5863

5864
void emit_package_scope(vcode_reg_t locus)
72✔
5865
{
5866
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
72✔
5867
   vcode_add_arg(op, locus);
72✔
5868

5869
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
72✔
5870
                "locus argument to package scope must be a debug locus");
5871
}
72✔
5872

5873
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
1,103✔
5874
{
5875
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
1,103✔
5876
   vcode_add_arg(op, locus);
1,103✔
5877
   op->type = type;
1,103✔
5878

5879
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,103✔
5880
                "locus argument to array scope must be a debug locus");
5881
}
1,103✔
5882

5883
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
2,961✔
5884
{
5885
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
2,961✔
5886
   vcode_add_arg(op, locus);
2,961✔
5887
   op->type = type;
2,961✔
5888

5889
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,961✔
5890
                "locus argument to record scope must be a debug locus");
5891
}
2,961✔
5892

5893
void emit_pop_scope(void)
4,136✔
5894
{
5895
   vcode_add_op(VCODE_OP_POP_SCOPE);
4,136✔
5896
}
4,136✔
5897

5898
vcode_reg_t emit_debug_locus(object_t *obj)
264,423✔
5899
{
5900
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
11,131,810✔
5901
      if (other->object == obj)
1,397,341✔
5902
         return other->result;
27,459✔
5903
   }
5904

5905
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
236,964✔
5906
   op->object = obj;
236,964✔
5907
   op->result = vcode_add_reg(vtype_debug_locus(), VCODE_INVALID_STAMP);
236,964✔
5908

5909
   return op->result;
236,964✔
5910
}
5911

UNCOV
5912
void emit_debug_out(vcode_reg_t reg)
×
5913
{
UNCOV
5914
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
UNCOV
5915
   vcode_add_arg(op, reg);
×
UNCOV
5916
}
×
5917

5918
void emit_cover_stmt(vcode_reg_t counters, uint32_t tag)
1,617✔
5919
{
5920
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,617✔
5921
   vcode_add_arg(op, counters);
1,617✔
5922
   op->tag = tag;
1,617✔
5923

5924
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
1,617✔
5925
                "counters argument must be pointer");
5926
}
1,617✔
5927

5928
void emit_cover_branch(vcode_reg_t counters, uint32_t tag)
695✔
5929
{
5930
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
695✔
5931
   vcode_add_arg(op, counters);
695✔
5932
   op->tag = tag;
695✔
5933

5934
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
695✔
5935
                "counters argument must be pointer");
5936
}
695✔
5937

5938
void emit_cover_toggle(vcode_reg_t signal, vcode_reg_t count, uint32_t tag)
1,364✔
5939
{
5940
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
1,364✔
5941
   vcode_add_arg(op, signal);
1,364✔
5942
   vcode_add_arg(op, count);
1,364✔
5943
   op->tag = tag;
1,364✔
5944
}
1,364✔
5945

5946
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
18✔
5947
{
5948
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
18✔
5949
   vcode_add_arg(op, signal);
18✔
5950
   vcode_add_arg(op, low);
18✔
5951
   op->tag = tag;
18✔
5952
}
18✔
5953

5954
void emit_cover_expr(vcode_reg_t counters, uint32_t tag)
1,144✔
5955
{
5956
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
1,144✔
5957
   vcode_add_arg(op, counters);
1,144✔
5958
   op->tag = tag;
1,144✔
5959

5960
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
1,144✔
5961
                "counters argument must be pointer");
5962
}
1,144✔
5963

5964
void emit_unreachable(vcode_reg_t locus)
1,987✔
5965
{
5966
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
1,987✔
5967
   if (locus != VCODE_INVALID_REG)
1,987✔
5968
      vcode_add_arg(op, locus);
171✔
5969
}
1,987✔
5970

5971
vcode_reg_t emit_undefined(vcode_type_t type, vcode_stamp_t stamp)
34✔
5972
{
5973
   active_unit->flags |= UNIT_UNDEFINED;
34✔
5974

5975
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
34✔
5976
   op->result = vcode_add_reg(type, stamp);
34✔
5977

5978
   return op->result;
34✔
5979
}
5980

5981
void emit_debug_info(const loc_t *loc)
4,161,623✔
5982
{
5983
   if (!loc_invalid_p(loc))
4,161,623✔
5984
      vcode_block_data()->last_loc = *loc;
4,130,582✔
5985
}
4,161,623✔
5986

5987
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
13,740✔
5988
{
5989
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
514,334✔
5990
      if (other->args.items[0] == context && other->ident == name)
18,707✔
5991
         return other->result;
6,592✔
5992
   }
5993

5994
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
7,148✔
5995
   vcode_add_arg(op, context);
7,148✔
5996
   op->ident = name;
7,148✔
5997

5998
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
7,148✔
5999
                "first argument to link var must be context");
6000

6001
   vcode_stamp_t stamp = VCODE_INVALID_STAMP;
7,148✔
6002

6003
   if (vtype_kind(type) == VCODE_TYPE_CARRAY)
7,148✔
6004
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)), stamp);
798✔
6005
   else
6006
      op->result = vcode_add_reg(vtype_pointer(type), stamp);
6,350✔
6007

6008
   return op->result;
7,148✔
6009
}
6010

6011
vcode_reg_t emit_link_package(ident_t name)
17,270✔
6012
{
6013
   VCODE_FOR_EACH_OP(other) {
628,412✔
6014
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
619,467✔
6015
         return other->result;
7,760✔
6016
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
611,707✔
6017
         return other->result;
565✔
6018
   }
6019

6020
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
8,945✔
6021
   op->ident = name;
8,945✔
6022

6023
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
8,945✔
6024

6025
   vcode_type_t type = vtype_context(name);
8,945✔
6026
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
8,945✔
6027
}
6028

6029
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
1,176✔
6030
{
6031
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
2,896✔
UNCOV
6032
      if (other->args.items[0] == state)
×
6033
         return;
6034
   }
6035

6036
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
1,176✔
6037
   vcode_add_arg(op, state);
1,176✔
6038
   if (strong != VCODE_INVALID_REG)
1,176✔
6039
      vcode_add_arg(op, strong);
48✔
6040

6041
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
1,176✔
6042
                "state must have integer type");
6043
   VCODE_ASSERT(strong == VCODE_INVALID_REG
1,176✔
6044
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
6045
                "strong argument not is not boolean");
6046
}
6047

6048
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
68✔
6049
                               vcode_reg_t locus, vcode_reg_t bounds)
6050
{
6051
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
68✔
6052
   vcode_add_arg(op, value);
68✔
6053
   vcode_add_arg(op, context);
68✔
6054
   vcode_add_arg(op, locus);
68✔
6055
   if (bounds != VCODE_INVALID_REG)
68✔
6056
      vcode_add_arg(op, bounds);
8✔
6057

6058
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
68✔
6059
                "invalid reflect value context argument");
6060
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
68✔
6061
                "locus argument to reflect value must be a debug locus");
6062

6063
   vcode_type_t type = vtype_access(vtype_opaque());
68✔
6064
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
68✔
6065
}
6066

6067
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
68✔
6068
                                 vcode_reg_t bounds)
6069
{
6070
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
68✔
6071
   vcode_add_arg(op, context);
68✔
6072
   vcode_add_arg(op, locus);
68✔
6073
   if (bounds != VCODE_INVALID_REG)
68✔
6074
      vcode_add_arg(op, bounds);
12✔
6075

6076
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
68✔
6077
                "invalid reflect value context argument");
6078
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
68✔
6079
                "locus argument to reflect value must be a debug locus");
6080

6081
   vcode_type_t type = vtype_access(vtype_opaque());
68✔
6082
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
68✔
6083
}
6084

6085
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
356✔
6086
                                  int nargs)
6087
{
6088
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
356✔
6089
   op->func = func;
356✔
6090

6091
   for (int i = 0; i < nargs; i++)
828✔
6092
      vcode_add_arg(op, args[i]);
472✔
6093

6094
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
356✔
6095
}
6096

6097
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
45✔
6098
{
6099
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
45✔
6100
   vcode_add_arg(op, left);
45✔
6101
   vcode_add_arg(op, right);
45✔
6102

6103
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
45✔
6104
                "or trigger left argument must be trigger");
6105
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
45✔
6106
                "or trigger right argument must be trigger");
6107

6108
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
45✔
6109
}
6110

6111
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
86✔
6112
{
6113
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
86✔
6114
   vcode_add_arg(op, left);
86✔
6115
   vcode_add_arg(op, right);
86✔
6116

6117
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
86✔
6118
                "cmp trigger left argument must be signal");
6119
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
86✔
6120
                "cmp trigger right argument must be integer");
6121

6122
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
86✔
6123
}
6124

6125
void emit_add_trigger(vcode_reg_t trigger)
501✔
6126
{
6127
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
501✔
6128
   vcode_add_arg(op, trigger);
501✔
6129

6130
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
501✔
6131
                "add trigger argument must be trigger");
6132
}
501✔
6133

6134
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
239✔
6135
                               vcode_type_t type, vcode_stamp_t stamp,
6136
                               const vcode_reg_t *args, int nargs)
6137
{
6138
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
239✔
6139
   op->type  = type;
239✔
6140
   op->ident = scope;
239✔
6141
   vcode_add_arg(op, locus);
239✔
6142
   for (int i = 0; i < nargs; i++)
279✔
6143
      vcode_add_arg(op, args[i]);
40✔
6144

6145
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
239✔
6146
                "bind external argument must be locus");
6147

6148
   op->result = vcode_add_reg(vtype_pointer(type), VCODE_INVALID_STAMP);
239✔
6149
   vcode_reg_data(op->result)->stamp = stamp;
239✔
6150
   return op->result;
239✔
6151
}
6152

6153
void emit_put_driver(vcode_reg_t target, vcode_reg_t count, vcode_reg_t values)
667✔
6154
{
6155
   op_t *op = vcode_add_op(VCODE_OP_PUT_DRIVER);
667✔
6156
   vcode_add_arg(op, target);
667✔
6157
   vcode_add_arg(op, count);
667✔
6158
   vcode_add_arg(op, values);
667✔
6159

6160
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
667✔
6161
                "put driver target is not signal");
6162
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
667✔
6163
                "put driver count is not offset type");
6164
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
667✔
6165
                "signal cannot be values argument for put driver");
6166
}
667✔
6167

6168
void emit_deposit_signal(vcode_reg_t target, vcode_reg_t count,
33✔
6169
                         vcode_reg_t values)
6170
{
6171
   op_t *op = vcode_add_op(VCODE_OP_DEPOSIT_SIGNAL);
33✔
6172
   vcode_add_arg(op, target);
33✔
6173
   vcode_add_arg(op, count);
33✔
6174
   vcode_add_arg(op, values);
33✔
6175

6176
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
33✔
6177
                "deposit signal target is not signal");
6178
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
33✔
6179
                "deposit signal count is not offset type");
6180
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
33✔
6181
                "signal cannot be values argument for deposit signal");
6182
}
33✔
6183

6184
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
1,500✔
6185
{
6186
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
1,500✔
6187
   vcode_add_arg(op, spec);
1,500✔
6188
   vcode_add_arg(op, length);
1,500✔
6189
   if (locus != VCODE_INVALID_REG)
1,500✔
6190
      vcode_add_arg(op, locus);
1,278✔
6191

6192
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
1,500✔
6193
                "spec argument to bind foreign must be a pointer");
6194
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
1,500✔
6195
                "length argument to bind foreign must be offset");
6196
   VCODE_ASSERT(locus == VCODE_INVALID_REG
1,500✔
6197
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6198
                "locus argument to bind foreign value must be a debug locus");
6199
}
1,500✔
6200

6201
vcode_reg_t emit_instance_name(vcode_reg_t kind)
7,280✔
6202
{
6203
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
7,280✔
6204
   vcode_add_arg(op, kind);
7,280✔
6205

6206
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
7,280✔
6207
                "kind argument to instance name must be offset");
6208

6209
   vcode_type_t type = vtype_uarray(1, vtype_char());
7,280✔
6210
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
7,280✔
6211
}
6212

6213
vcode_reg_t emit_get_counters(ident_t block)
1,065✔
6214
{
6215
   op_t *op = vcode_add_op(VCODE_OP_GET_COUNTERS);
1,065✔
6216
   op->ident = block;
1,065✔
6217

6218
   vcode_type_t vint32 = vtype_int(INT32_MIN, INT32_MAX);
1,065✔
6219
   vcode_type_t type = vtype_pointer(vint32);
1,065✔
6220
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
1,065✔
6221
}
6222

6223
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
14,452✔
6224
{
6225
   vcode_state_t state;
14,452✔
6226
   vcode_state_save(&state);
14,452✔
6227

6228
   vcode_select_unit(vu);
14,452✔
6229

6230
   const int nblocks = vcode_count_blocks();
14,452✔
6231
   for (int i = 0; i < nblocks; i++) {
36,349✔
6232
      vcode_select_block(i);
21,897✔
6233

6234
      const int nops = vcode_count_ops();
21,897✔
6235
      for (int op = 0; op < nops; op++) {
435,738✔
6236
         switch (vcode_get_op(op)) {
413,841✔
6237
         case VCODE_OP_LINK_PACKAGE:
504✔
6238
            (*fn)(vcode_get_ident(op), ctx);
504✔
6239
            break;
504✔
6240
         case VCODE_OP_FCALL:
15,963✔
6241
         case VCODE_OP_PCALL:
6242
         case VCODE_OP_CLOSURE:
6243
         case VCODE_OP_PROTECTED_INIT:
6244
         case VCODE_OP_PACKAGE_INIT:
6245
         case VCODE_OP_FUNCTION_TRIGGER:
6246
            (*fn)(vcode_get_func(op), ctx);
15,963✔
6247
            break;
15,963✔
6248
         default:
6249
            break;
6250
         }
6251
      }
6252
   }
6253

6254
   vcode_state_restore(&state);
14,452✔
6255
}
14,452✔
6256

6257
#if VCODE_CHECK_UNIONS
6258
#define OP_USE_COUNT_U0(x)                                              \
6259
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6260
#define OP_USE_COUNT_U1(x)                                              \
6261
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6262
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6263
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6264

6265
__attribute__((constructor))
6266
static void vcode_check_unions(void)
6267
{
6268
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6269
   for (int i = 0; i < 256; i++) {
6270
      assert(OP_USE_COUNT_U0(i) <= 1);
6271
      assert(OP_USE_COUNT_U1(i) <= 1);
6272
   }
6273
}
6274
#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