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

nickg / nvc / 24238351848

10 Apr 2026 10:22AM UTC coverage: 92.348% (+0.01%) from 92.338%
24238351848

Pull #1488

github

web-flow
Merge 198926fb5 into e00449bb3
Pull Request #1488: Verilog: implement $info, $warning, $error and fix $fatal format strings

1156 of 1216 new or added lines in 23 files covered. (95.07%)

1443 existing lines in 24 files now uncovered.

76369 of 82697 relevant lines covered (92.35%)

609386.16 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,687,821✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_block);
464,143✔
38
DECLARE_AND_DEFINE_ARRAY(vcode_type);
124,642✔
39

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

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

107
DECLARE_AND_DEFINE_ARRAY(op);
17,073,717✔
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,182✔
179
DECLARE_AND_DEFINE_ARRAY(var);
742,728✔
180
DECLARE_AND_DEFINE_ARRAY(reg);
13,099,749✔
181
DECLARE_AND_DEFINE_ARRAY(block);
191,633✔
182
DECLARE_AND_DEFINE_ARRAY(vtype);
33,690,303✔
183
DECLARE_AND_DEFINE_ARRAY(vstamp);
2,094,940✔
184

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

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

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

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

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

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

233
#define VCODE_CHECK_UNIONS 0
234

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

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

244
   return result;
245
}
246

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

253
   return result;
254
}
255

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

262
   return result;
263
}
264

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

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

275
   return reg;
2,076,740✔
276
}
277

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

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

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

294
   block_t *block = vcode_block_data();
2,699,068✔
295

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

302
   return op;
2,699,068✔
303
}
304

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

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

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

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

324
static op_t *vcode_find_definition(vcode_reg_t reg)
2,837,872✔
325
{
326
   for (int i = active_block; i >= 0; i--) {
2,875,983✔
327
      block_t *b = &(active_unit->blocks.items[i]);
2,874,432✔
328
      for (int j = b->ops.count - 1; j >= 0; j--) {
58,184,413✔
329
         if (b->ops.items[j].result == reg)
58,146,302✔
330
            return &(b->ops.items[j]);
2,836,321✔
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,816,866✔
339
{
340
   op_t *defn = vcode_find_definition(reg);
2,816,866✔
341
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
2,816,866✔
342
                what, reg);
343
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
2,816,866✔
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,816,866✔
352
#endif
353

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

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

367
   int depth = MASK_CONTEXT(type);
8,288,834✔
368
   assert(depth <= unit->depth);
8,288,834✔
369
   while (depth != unit->depth)
9,496,025✔
370
      unit = unit->context;
1,207,191✔
371

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

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

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

383
   int depth = MASK_CONTEXT(stamp);
1,607,980✔
384
   assert(depth <= unit->depth);
1,607,980✔
385
   while (depth != unit->depth)
1,650,006✔
386
      unit = unit->context;
42,026✔
387

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

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

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

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

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

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

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

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

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

441
         vcode_select_unit(vu);
808✔
442

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

445
         vcode_state_restore(&state);
808✔
446
      }
447
      break;
808✔
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,636✔
454
   case VCODE_OP_UNWRAP:
455
   case VCODE_OP_RESOLVED:
456
      vcode_heap_allocate(defn->args.items[0]);
5,636✔
457
      break;
5,636✔
458

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

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

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

476
               VCODE_ASSERT(
271,579✔
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,729✔
486
         const vtype_kind_t rkind = vcode_reg_kind(reg);
5,737✔
487
         if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
5,737✔
488
            // Function may return a pointer to its argument
489
            vcode_heap_allocate(defn->args.items[i]);
5,599✔
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,054✔
559
{
560
   state->unit  = active_unit;
59,054✔
561
   state->block = active_block;
59,054✔
562
}
59,054✔
563

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

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

574
   if (unit == active_unit)
74,762✔
575
      vcode_close();
14,304✔
576

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

583
   if (unit->context != NULL) {
74,762✔
584
      vcode_unit_t *it = &(unit->context->children);
20,343✔
585
      for (; *it != NULL && *it != unit; it = &((*it)->next))
52,713✔
586
         ;
587
      assert(*it != NULL);
20,343✔
588
      *it = (*it)->next;
20,343✔
589
   }
590

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

594
      for (unsigned j = 0; j < b->ops.count; j++) {
2,776,085✔
595
         op_t *o = &(b->ops.items[j]);
2,584,478✔
596
         if (OP_HAS_COMMENT(o->kind))
2,584,478✔
597
            free(o->comment);
300,953✔
598
         if (OP_HAS_TARGET(o->kind))
2,584,478✔
599
            free(o->targets.items);
109,275✔
600
         free(o->args.items);
2,584,478✔
601
      }
602
      free(b->ops.items);
191,607✔
603
   }
604
   free(unit->blocks.items);
74,762✔
605

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

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

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

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

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

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

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

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

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

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

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

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

663
   if (s->u.intg.low == s->u.intg.high) {
948,543✔
664
      if (value) *value = s->u.intg.low;
734,944✔
665
      return true;
734,944✔
666
   }
667
   else
668
      return false;
669
}
670

671
bool vcode_reg_bounds(vcode_reg_t reg, int64_t *low, int64_t *high)
570,217✔
672
{
673
   reg_t *r = vcode_reg_data(reg);
570,217✔
674
   if (r->stamp == VCODE_INVALID_STAMP) {
570,217✔
675
      vtype_t *t = vcode_type_data(r->type);
101,923✔
676
      if (t->kind == VCODE_TYPE_INT || t->kind == VCODE_TYPE_OFFSET) {
101,923✔
677
         *low = t->low;
100,542✔
678
         *high = t->high;
100,542✔
679
         return true;
100,542✔
680
      }
681
   }
682
   else {
683
      vstamp_t *s = vcode_stamp_data(r->stamp);
468,294✔
684
      if (s->kind == VCODE_STAMP_INT) {
468,294✔
685
         *low = s->u.intg.low;
467,754✔
686
         *high = s->u.intg.high;
467,754✔
687
         return true;
467,754✔
688
      }
689
   }
690

691
   return false;
692
}
693

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

714
   return false;
715
}
716

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

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

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

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

731
         for (int j = b->ops.count - 1; j >= 0; j--) {
5,095,137✔
732
            op_t *o = &(b->ops.items[j]);
4,781,025✔
733

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

796
            default:
797
               break;
798
            }
799

800
            for (int k = 0; k < o->args.count; k++) {
14,286,795✔
801
               if (o->args.items[k] != VCODE_INVALID_REG)
9,505,770✔
802
                  uses[o->args.items[k]]++;
9,458,312✔
803
            }
804
         }
805
      }
806
   } while (pruned > 0);
105,995✔
807

808
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
266,421✔
809
      block_t *b = &(active_unit->blocks.items[i]);
191,633✔
810
      op_t *dst = &(b->ops.items[0]);
191,633✔
811
      size_t copied = 0;
191,633✔
812
      for (int j = 0; j < b->ops.count; j++) {
2,890,701✔
813
         const op_t *src = &(b->ops.items[j]);
2,699,068✔
814
         if (src->kind != (vcode_op_t)-1) {
2,699,068✔
815
            if (src != dst) {
2,584,615✔
816
               assert(dst < src);
875,423✔
817
               *dst = *src;
875,423✔
818
            }
819
            dst++;
2,584,615✔
820
            copied++;
2,584,615✔
821
         }
822
      }
823

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

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

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

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

848
int vcode_count_vars(void)
74,765✔
849
{
850
   assert(active_unit != NULL);
74,765✔
851
   return active_unit->vars.count;
74,765✔
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)
130,531✔
866
{
867
   return vcode_var_data(var)->name;
130,531✔
868
}
869

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

992
vcode_block_t vcode_get_target(int op, int nth)
154,839✔
993
{
994
   op_t *o = vcode_op_data(op);
154,839✔
995
   assert(OP_HAS_TARGET(o->kind));
154,839✔
996
   return vcode_block_array_nth(&(o->targets), nth);
154,839✔
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,854,330✔
1008
{
1009
   assert(active_unit != NULL);
2,854,330✔
1010
   assert(active_block != VCODE_INVALID_BLOCK);
2,854,330✔
1011

1012
   const block_t *b = &(active_unit->blocks.items[active_block]);
2,854,330✔
1013
   if (b->ops.count == 0)
2,854,330✔
1014
      return false;
1015
   else {
1016
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
2,598,453✔
1017
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
2,598,453✔
1018
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
2,598,429✔
1019
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
1020
         || kind == VCODE_OP_UNREACHABLE;
5,196,882✔
1021
   }
1022
}
1023

1024
const char *vcode_op_string(vcode_op_t op)
175,833✔
1025
{
1026
   static const char *strs[] = {
175,833✔
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))
175,833✔
1056
      return "???";
1057
   else
1058
      return strs[op];
175,833✔
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("+%u", op->tag);
2230
            }
2231
            break;
2232

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

2243
         case VCODE_OP_UNDEFINED:
2244
            {
2245
               col += vcode_dump_reg(op->result);
2246
               col += printf(" := %s", vcode_op_string(op->kind));
2247
               vcode_dump_result_type(col, op);
2248
            }
2249
            break;
2250

2251
         case VCODE_OP_RANGE_LENGTH:
2252
         case VCODE_OP_RANGE_NULL:
2253
            {
2254
               col += vcode_dump_reg(op->result);
2255
               col += printf(" := %s left ", vcode_op_string(op->kind));
2256
               vcode_dump_reg(op->args.items[0]);
2257
               col += printf(" right ");
2258
               vcode_dump_reg(op->args.items[1]);
2259
               col += printf(" dir ");
2260
               col += vcode_dump_reg(op->args.items[2]);
2261
               vcode_dump_result_type(col, op);
2262
            }
2263
            break;
2264

2265
         case VCODE_OP_LINK_PACKAGE:
2266
            {
2267
               col += vcode_dump_reg(op->result);
2268
               col += nvc_printf(" := %s $magenta$%s$$",
2269
                                 vcode_op_string(op->kind), istr(op->ident));
2270
               if (op->args.count > 0) {
2271
                  col += printf(" locus ");
2272
                  col += vcode_dump_reg(op->args.items[0]);
2273
               }
2274
               vcode_dump_result_type(col, op);
2275
            }
2276
            break;
2277

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

2288
         case VCODE_OP_UNREACHABLE:
2289
            {
2290
               printf("%s", vcode_op_string(op->kind));
2291
               if (op->args.count > 0) {
2292
                  printf(" ");
2293
                  vcode_dump_reg(op->args.items[0]);
2294
               }
2295
            }
2296
            break;
2297

2298
         case VCODE_OP_DEBUG_LOCUS:
2299
            {
2300
               col += vcode_dump_reg(op->result);
2301
               col += nvc_printf(" := %s $magenta$", vcode_op_string(op->kind));
2302

2303
               tree_t t = tree_from_object(op->object);
2304
               if (t != NULL)
2305
                  col += printf("%s@", tree_kind_str(tree_kind(t)));
2306

2307
               col += nvc_printf("%p$$", op->object);
2308
               vcode_dump_result_type(col, op);
2309
            }
2310
            break;
2311

2312
         case VCODE_OP_ENTER_STATE:
2313
            {
2314
               printf("%s ", vcode_op_string(op->kind));
2315
               vcode_dump_reg(op->args.items[0]);
2316
               if (op->args.count > 1) {
2317
                  printf(" strong ");
2318
                  vcode_dump_reg(op->args.items[1]);
2319
               }
2320
            }
2321
            break;
2322

2323
         case VCODE_OP_REFLECT_VALUE:
2324
            {
2325
               col += vcode_dump_reg(op->result);
2326
               col += printf(" := %s ", vcode_op_string(op->kind));
2327
               vcode_dump_reg(op->args.items[0]);
2328
               col += printf(" context ");
2329
               vcode_dump_reg(op->args.items[1]);
2330
               col += printf(" locus ");
2331
               col += vcode_dump_reg(op->args.items[2]);
2332
               if (op->args.count > 3) {
2333
                  col += printf(" bounds ");
2334
                  col += vcode_dump_reg(op->args.items[3]);
2335
               }
2336
               vcode_dump_result_type(col, op);
2337
            }
2338
            break;
2339

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

2355
         case VCODE_OP_FUNCTION_TRIGGER:
2356
            {
2357
               col += vcode_dump_reg(op->result);
2358
               col += nvc_printf(" := %s $magenta$%s$$ ",
2359
                                 vcode_op_string(op->kind), istr(op->func));
2360
               for (int i = 0; i < op->args.count; i++) {
2361
                  if (i > 0) col += printf(", ");
2362
                  col += vcode_dump_reg(op->args.items[i]);
2363
               }
2364
               vcode_dump_result_type(col, op);
2365
            }
2366
            break;
2367

2368
         case VCODE_OP_OR_TRIGGER:
2369
         case VCODE_OP_CMP_TRIGGER:
2370
            {
2371
               col += vcode_dump_reg(op->result);
2372
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
2373
               col += vcode_dump_reg(op->args.items[0]);
2374
               if (op->kind == VCODE_OP_OR_TRIGGER)
2375
                  col += printf(" || ");
2376
               else
2377
                  col += printf(" == ");
2378
               col += vcode_dump_reg(op->args.items[1]);
2379
               vcode_dump_result_type(col, op);
2380
            }
2381
            break;
2382

2383
         case VCODE_OP_ADD_TRIGGER:
2384
            {
2385
               printf("%s ", vcode_op_string(op->kind));
2386
               vcode_dump_reg(op->args.items[0]);
2387
            }
2388
            break;
2389

2390
         case VCODE_OP_BIND_FOREIGN:
2391
            {
2392
               nvc_printf("%s ", vcode_op_string(op->kind));
2393
               vcode_dump_reg(op->args.items[0]);
2394
               printf(" length ");
2395
               vcode_dump_reg(op->args.items[1]);
2396
               if (op->args.count > 2) {
2397
                  printf(" locus ");
2398
                  vcode_dump_reg(op->args.items[1]);
2399
               }
2400
            }
2401
            break;
2402

2403
         case VCODE_OP_INSTANCE_NAME:
2404
         case VCODE_OP_BIND_EXTERNAL:
2405
            {
2406
               col += vcode_dump_reg(op->result);
2407
               col += nvc_printf(" := %s ", vcode_op_string(op->kind));
2408
               col += vcode_dump_reg(op->args.items[0]);
2409
               col += nvc_printf(" scope $magenta$%s$$ ", istr(op->ident));
2410
               for (int i = 1; i < op->args.count; i++) {
2411
                  if (i > 1) col += printf(", ");
2412
                  col += vcode_dump_reg(op->args.items[i]);
2413
               }
2414
               vcode_dump_result_type(col, op);
2415
            }
2416
            break;
2417

2418
         case VCODE_OP_GET_COUNTERS:
2419
            {
2420
               col += vcode_dump_reg(op->result);
2421
               col += nvc_printf(":= %s $magenta$%s$$",
2422
                                 vcode_op_string(op->kind), istr(op->ident));
2423
               vcode_dump_result_type(col, op);
2424
            }
2425
            break;
2426
         }
2427

2428
         if (j == mark_op && i == old_block)
2429
            nvc_printf("\t $red$<----$$");
2430

2431
         nvc_printf("$$\n");
2432

2433
         if (callback != NULL)
2434
            (*callback)(j, arg);
2435
      }
2436

2437
      if (b->ops.count == 0)
2438
         nvc_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2439
   }
2440

2441
   printf("\n");
2442
   fflush(stdout);
2443

2444
   active_block = old_block;
2445
}
2446
LCOV_EXCL_STOP
2447

2448
static inline bool vtype_eq_internal(const vtype_t *at, const vtype_t *bt)
21,815,253✔
2449
{
2450
   if (at->kind != bt->kind)
21,815,253✔
2451
      return false;
2452

2453
   switch (at->kind) {
5,709,069✔
2454
   case VCODE_TYPE_INT:
3,804,299✔
2455
      return (at->low == bt->low) && (at->high == bt->high);
5,429,364✔
2456
   case VCODE_TYPE_REAL:
75,942✔
2457
      return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
76,003✔
2458
   case VCODE_TYPE_CARRAY:
163,745✔
2459
      return at->size == bt->size && vtype_eq(at->elem, bt->elem);
175,366✔
2460
   case VCODE_TYPE_UARRAY:
119,937✔
2461
      return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
149,458✔
2462
   case VCODE_TYPE_POINTER:
710,595✔
2463
   case VCODE_TYPE_ACCESS:
2464
      return vtype_eq(at->pointed, bt->pointed);
710,595✔
2465
   case VCODE_TYPE_OFFSET:
2466
   case VCODE_TYPE_OPAQUE:
2467
   case VCODE_TYPE_DEBUG_LOCUS:
2468
   case VCODE_TYPE_TRIGGER:
2469
      return true;
2470
   case VCODE_TYPE_RESOLUTION:
126,084✔
2471
   case VCODE_TYPE_CLOSURE:
2472
   case VCODE_TYPE_SIGNAL:
2473
   case VCODE_TYPE_FILE:
2474
      return vtype_eq(at->base, bt->base);
126,084✔
2475
   case VCODE_TYPE_RECORD:
90,557✔
2476
   case VCODE_TYPE_CONTEXT:
2477
      return at->name == bt->name;
90,557✔
UNCOV
2478
   default:
×
2479
      should_not_reach_here();
2480
   }
2481
}
2482

2483
bool vtype_eq(vcode_type_t a, vcode_type_t b)
7,444,676✔
2484
{
2485
   assert(active_unit != NULL);
7,444,676✔
2486

2487
   if (a == b)
7,444,676✔
2488
      return true;
2489
   else if (MASK_CONTEXT(a) == MASK_CONTEXT(b))
1,462,868✔
2490
      return false;   // Guaranteed by vtype_new
2491
   else {
2492
      const vtype_t *at = vcode_type_data(a);
174,316✔
2493
      const vtype_t *bt = vcode_type_data(b);
174,316✔
2494

2495
      return vtype_eq_internal(at, bt);
174,316✔
2496
   }
2497
}
2498

UNCOV
2499
void vcode_dump(void)
×
2500
{
UNCOV
2501
   vcode_dump_with_mark(-1, NULL, NULL);
×
UNCOV
2502
}
×
2503

2504
static vcode_type_t vtype_new(vtype_t *new)
3,760,532✔
2505
{
2506
   const int index = active_unit->types.count - 1;
3,760,532✔
2507

2508
   for (int i = 0; i < index; i++) {
22,129,012✔
2509
      const vtype_t *cmp = vtype_array_nth_ptr(&(active_unit->types), i);
21,640,937✔
2510
      if (vtype_eq_internal(new, cmp)) {
21,640,937✔
2511
         active_unit->types.count--;
3,272,457✔
2512
         return MAKE_HANDLE(active_unit->depth, i);
3,272,457✔
2513
      }
2514
   }
2515

2516
   return MAKE_HANDLE(active_unit->depth, index);
488,075✔
2517
}
2518

2519
vcode_type_t vtype_int(int64_t low, int64_t high)
2,271,412✔
2520
{
2521
   assert(active_unit != NULL);
2,271,412✔
2522

2523
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
2,271,412✔
2524
   n->kind = VCODE_TYPE_INT;
2,271,412✔
2525
   n->low  = low;
2,271,412✔
2526
   n->high = high;
2,271,412✔
2527

2528
   switch (bits_for_range(low, high)) {
2,271,412✔
2529
   case 64:
79,674✔
2530
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
79,674✔
2531
      break;
79,674✔
2532
   case 32:
505,327✔
2533
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
505,327✔
2534
      break;
505,327✔
2535
   case 16:
243✔
2536
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
243✔
2537
      break;
243✔
2538
   case 8:
1,062,362✔
2539
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
1,062,362✔
2540
      break;
1,062,362✔
2541
   case 1:
623,806✔
2542
      n->repr = VCODE_REPR_U1;
623,806✔
2543
      break;
623,806✔
UNCOV
2544
   case 0:
×
UNCOV
2545
      n->repr = VCODE_REPR_I64;    // Null range
×
UNCOV
2546
      break;
×
UNCOV
2547
   default:
×
2548
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2549
   }
2550

2551
   return vtype_new(n);
2,271,412✔
2552
}
2553

2554
vcode_type_t vtype_bool(void)
479,870✔
2555
{
2556
   return vtype_int(0, 1);
479,870✔
2557
}
2558

2559
vcode_type_t vtype_carray(int size, vcode_type_t elem)
89,894✔
2560
{
2561
   assert(active_unit != NULL);
89,894✔
2562

2563
   const vtype_kind_t ekind = vtype_kind(elem);
89,894✔
2564
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
89,894✔
2565
                "array types may not be nested");
2566

2567
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
89,894✔
2568
   memset(n, '\0', sizeof(vtype_t));
89,894✔
2569
   n->kind   = VCODE_TYPE_CARRAY;
89,894✔
2570
   n->elem   = elem;
89,894✔
2571
   n->size   = MAX(size, 0);
89,894✔
2572

2573
   return vtype_new(n);
89,894✔
2574
}
2575

2576
vcode_type_t vtype_find_named_record(ident_t name)
44,526✔
2577
{
2578
   assert(active_unit != NULL);
44,526✔
2579

2580
   for (int i = 0; i < active_unit->types.count; i++) {
418,911✔
2581
      vtype_t *other = &(active_unit->types.items[i]);
401,227✔
2582
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
401,227✔
2583
         return MAKE_HANDLE(active_unit->depth, i);
26,842✔
2584
   }
2585

2586
   return VCODE_INVALID_TYPE;
2587
}
2588

2589
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
17,684✔
2590
                                int nfields)
2591
{
2592
   assert(active_unit != NULL);
17,684✔
2593

2594
   vtype_t *data = NULL;
17,684✔
2595
   vcode_type_t handle = vtype_find_named_record(name);
17,684✔
2596
   if (handle == VCODE_INVALID_TYPE) {
17,684✔
2597
      data = vtype_array_alloc(&(active_unit->types));
8,842✔
2598
      memset(data, '\0', sizeof(vtype_t));
8,842✔
2599
      data->kind = VCODE_TYPE_RECORD;
8,842✔
2600
      data->name = name;
8,842✔
2601

2602
      handle = vtype_new(data);
8,842✔
2603
   }
2604
   else {
2605
      data = vcode_type_data(handle);
8,842✔
2606
      VCODE_ASSERT(data->fields.count == 0,
8,842✔
2607
                    "record type %s already defined", istr(name));
2608
   }
2609

2610
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
17,684✔
2611
   for (int i = 0; i < nfields; i++)
47,127✔
2612
      vcode_type_array_add(&(data->fields), field_types[i]);
29,443✔
2613

2614
   return handle;
17,684✔
2615
}
2616

2617
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem)
116,494✔
2618
{
2619
   assert(active_unit != NULL);
116,494✔
2620

2621
   const vtype_kind_t ekind = vtype_kind(elem);
116,494✔
2622
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
116,494✔
2623
                "array types may not be nested");
2624

2625
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
116,494✔
2626

2627
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
116,494✔
2628
   memset(n, '\0', sizeof(vtype_t));
116,494✔
2629
   n->kind = VCODE_TYPE_UARRAY;
116,494✔
2630
   n->elem = elem;
116,494✔
2631
   n->dims = ndim;
116,494✔
2632

2633
   return vtype_new(n);
116,494✔
2634
}
2635

2636
vcode_type_t vtype_pointer(vcode_type_t to)
301,368✔
2637
{
2638
   assert(active_unit != NULL);
301,368✔
2639

2640
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
301,368✔
2641
   n->kind    = VCODE_TYPE_POINTER;
301,368✔
2642
   n->pointed = to;
301,368✔
2643

2644
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
301,368✔
2645
                "cannot get pointer to carray type");
2646

2647
   return vtype_new(n);
301,368✔
2648
}
2649

2650
vcode_type_t vtype_access(vcode_type_t to)
10,504✔
2651
{
2652
   assert(active_unit != NULL);
10,504✔
2653

2654
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
10,504✔
2655
   n->kind    = VCODE_TYPE_ACCESS;
10,504✔
2656
   n->pointed = to;
10,504✔
2657

2658
   return vtype_new(n);
10,504✔
2659
}
2660

2661
vcode_type_t vtype_signal(vcode_type_t base)
67,056✔
2662
{
2663
   assert(active_unit != NULL);
67,056✔
2664

2665
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
67,056✔
2666
   n->kind = VCODE_TYPE_SIGNAL;
67,056✔
2667
   n->base = base;
67,056✔
2668

2669
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
67,056✔
2670

2671
   return vtype_new(n);
67,056✔
2672
}
2673

2674
vcode_type_t vtype_resolution(vcode_type_t base)
16,485✔
2675
{
2676
   assert(active_unit != NULL);
16,485✔
2677

2678
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
16,485✔
2679
   n->kind = VCODE_TYPE_RESOLUTION;
16,485✔
2680
   n->base = base;
16,485✔
2681

2682
   return vtype_new(n);
16,485✔
2683
}
2684

2685
vcode_type_t vtype_closure(vcode_type_t result)
11,810✔
2686
{
2687
   assert(active_unit != NULL);
11,810✔
2688

2689
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
11,810✔
2690
   n->kind = VCODE_TYPE_CLOSURE;
11,810✔
2691
   n->base = result;
11,810✔
2692

2693
   return vtype_new(n);
11,810✔
2694
}
2695

2696
vcode_type_t vtype_context(ident_t name)
81,704✔
2697
{
2698
   assert(active_unit != NULL);
81,704✔
2699
   assert(name != NULL);
81,704✔
2700

2701
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
81,704✔
2702
   n->kind = VCODE_TYPE_CONTEXT;
81,704✔
2703
   n->name = name;
81,704✔
2704

2705
   return vtype_new(n);
81,704✔
2706
}
2707

2708
vcode_type_t vtype_file(vcode_type_t base)
2,576✔
2709
{
2710
   assert(active_unit != NULL);
2,576✔
2711

2712
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
2,576✔
2713
   n->kind = VCODE_TYPE_FILE;
2,576✔
2714
   n->base = base;
2,576✔
2715

2716
   return vtype_new(n);
2,576✔
2717
}
2718

2719
vcode_type_t vtype_offset(void)
458,098✔
2720
{
2721
   assert(active_unit != NULL);
458,098✔
2722

2723
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
458,098✔
2724
   n->kind = VCODE_TYPE_OFFSET;
458,098✔
2725
   n->low  = INT64_MIN;
458,098✔
2726
   n->high = INT64_MAX;
458,098✔
2727
   n->repr = VCODE_REPR_I64;
458,098✔
2728

2729
   return vtype_new(n);
458,098✔
2730
}
2731

2732
vcode_type_t vtype_time(void)
19,302✔
2733
{
2734
   return vtype_int(INT64_MIN, INT64_MAX);
19,302✔
2735
}
2736

2737
vcode_type_t vtype_char(void)
24,185✔
2738
{
2739
   return vtype_int(0, 255);
24,185✔
2740
}
2741

2742
vcode_type_t vtype_opaque(void)
4,584✔
2743
{
2744
   assert(active_unit != NULL);
4,584✔
2745

2746
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
4,584✔
2747
   n->kind = VCODE_TYPE_OPAQUE;
4,584✔
2748

2749
   return vtype_new(n);
4,584✔
2750
}
2751

2752
vcode_type_t vtype_debug_locus(void)
234,073✔
2753
{
2754
   assert(active_unit != NULL);
234,073✔
2755

2756
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
234,073✔
2757
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
234,073✔
2758

2759
   return vtype_new(n);
234,073✔
2760
}
2761

2762
vcode_type_t vtype_trigger(void)
679✔
2763
{
2764
   assert(active_unit != NULL);
679✔
2765

2766
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
679✔
2767
   n->kind = VCODE_TYPE_TRIGGER;
679✔
2768

2769
   return vtype_new(n);
679✔
2770
}
2771

2772
vcode_type_t vtype_real(double low, double high)
84,953✔
2773
{
2774
   assert(active_unit != NULL);
84,953✔
2775

2776
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
84,953✔
2777
   n->kind  = VCODE_TYPE_REAL;
84,953✔
2778
   n->rlow  = low;
84,953✔
2779
   n->rhigh = high;
84,953✔
2780

2781
   return vtype_new(n);
84,953✔
2782
}
2783

2784
vtype_kind_t vtype_kind(vcode_type_t type)
5,839,086✔
2785
{
2786
   vtype_t *vt = vcode_type_data(type);
5,839,086✔
2787
   return vt->kind;
5,839,086✔
2788
}
2789

2790
vtype_repr_t vtype_repr(vcode_type_t type)
57,388✔
2791
{
2792
   vtype_t *vt = vcode_type_data(type);
57,388✔
2793
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
57,388✔
2794
   return vt->repr;
57,388✔
2795
}
2796

2797
vcode_type_t vtype_elem(vcode_type_t type)
201,331✔
2798
{
2799
   vtype_t *vt = vcode_type_data(type);
201,331✔
2800
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
201,331✔
2801
   return vt->elem;
201,331✔
2802
}
2803

2804
vcode_type_t vtype_base(vcode_type_t type)
90,574✔
2805
{
2806
   vtype_t *vt = vcode_type_data(type);
90,574✔
2807
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
90,574✔
2808
          || vt->kind == VCODE_TYPE_RESOLUTION
2809
          || vt->kind == VCODE_TYPE_CLOSURE);
2810
   return vt->base;
90,574✔
2811
}
2812

2813
unsigned vtype_dims(vcode_type_t type)
61,427✔
2814
{
2815
   vtype_t *vt = vcode_type_data(type);
61,427✔
2816
   assert(vt->kind == VCODE_TYPE_UARRAY);
61,427✔
2817
   return vt->dims;
61,427✔
2818
}
2819

2820
unsigned vtype_size(vcode_type_t type)
81,209✔
2821
{
2822
   vtype_t *vt = vcode_type_data(type);
81,209✔
2823
   assert(vt->kind == VCODE_TYPE_CARRAY);
81,209✔
2824
   return vt->size;
81,209✔
2825
}
2826

2827
int vtype_fields(vcode_type_t type)
12,169✔
2828
{
2829
   vtype_t *vt = vcode_type_data(type);
12,169✔
2830
   assert(vt->kind == VCODE_TYPE_RECORD);
12,169✔
2831
   return vt->fields.count;
12,169✔
2832
}
2833

2834
vcode_type_t vtype_field(vcode_type_t type, int field)
48,072✔
2835
{
2836
   vtype_t *vt = vcode_type_data(type);
48,072✔
2837
   assert(vt->kind == VCODE_TYPE_RECORD);
48,072✔
2838
   return vcode_type_array_nth(&(vt->fields), field);
48,072✔
2839
}
2840

2841
ident_t vtype_name(vcode_type_t type)
26,835✔
2842
{
2843
   vtype_t *vt = vcode_type_data(type);
26,835✔
2844
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
26,835✔
2845
   return vt->name;
26,835✔
2846
}
2847

2848
vcode_type_t vtype_pointed(vcode_type_t type)
488,626✔
2849
{
2850
   vtype_t *vt = vcode_type_data(type);
488,626✔
2851
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
488,626✔
2852
   return vt->pointed;
488,626✔
2853
}
2854

2855
int64_t vtype_low(vcode_type_t type)
119,282✔
2856
{
2857
   vtype_t *vt = vcode_type_data(type);
119,282✔
2858
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
119,282✔
2859
   return vt->low;
119,282✔
2860
}
2861

2862
int64_t vtype_high(vcode_type_t type)
120,075✔
2863
{
2864
   vtype_t *vt = vcode_type_data(type);
120,075✔
2865
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
120,075✔
2866
   return vt->high;
120,075✔
2867
}
2868

2869
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
2,556✔
2870
{
2871
   return vtype_kind(type) == VCODE_TYPE_POINTER
2,556✔
2872
      && vtype_kind(vtype_pointed(type)) == to;
2,556✔
2873
}
2874

2875
bool vtype_is_scalar(vcode_type_t type)
615,984✔
2876
{
2877
   const vtype_kind_t kind = vtype_kind(type);
615,984✔
2878
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
615,984✔
2879
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
249,403✔
2880
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2881
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2882
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER
2883
      || kind == VCODE_TYPE_RESOLUTION;
615,984✔
2884
}
2885

2886
bool vtype_is_numeric(vcode_type_t type)
24,865✔
2887
{
2888
   const vtype_kind_t kind = vtype_kind(type);
24,865✔
2889
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
24,865✔
2890
      || kind == VCODE_TYPE_REAL;
24,865✔
2891
}
2892

2893
bool vtype_is_integral(vcode_type_t type)
1,206✔
2894
{
2895
   const vtype_kind_t kind = vtype_kind(type);
1,206✔
2896
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET;
1,206✔
2897
}
2898

2899
bool vtype_is_composite(vcode_type_t type)
50,343✔
2900
{
2901
   const vtype_kind_t kind = vtype_kind(type);
50,343✔
2902
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
50,343✔
2903
}
2904

2905
bool vtype_is_signal(vcode_type_t type)
212,129✔
2906
{
2907
   vtype_t *vt = vcode_type_data(type);
377,785✔
2908
   switch (vt->kind) {
377,785✔
2909
   case VCODE_TYPE_SIGNAL:
2910
      return true;
2911
   case VCODE_TYPE_POINTER:
98,468✔
2912
      return vtype_is_signal(vt->pointed);
98,468✔
2913
   case VCODE_TYPE_RECORD:
2914
      for (int i = 0; i < vt->fields.count; i++) {
48,658✔
2915
         if (vtype_is_signal(vt->fields.items[i]))
38,309✔
2916
            return true;
2917
      }
2918
      return false;
2919
   case VCODE_TYPE_UARRAY:
67,188✔
2920
   case VCODE_TYPE_CARRAY:
2921
      return vtype_is_signal(vt->elem);
67,188✔
2922
   default:
162,738✔
2923
      return false;
162,738✔
2924
   }
2925
}
2926

UNCOV
2927
int vtype_repr_bits(vtype_repr_t repr)
×
2928
{
UNCOV
2929
   switch (repr) {
×
2930
   case VCODE_REPR_U1: return 1;
2931
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2932
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2933
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2934
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2935
   default: return -1;
2936
   }
2937
}
2938

2939
bool vtype_repr_signed(vtype_repr_t repr)
×
2940
{
UNCOV
2941
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
×
UNCOV
2942
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
×
2943
}
2944

2945
static int64_t vtype_repr_low(vtype_repr_t repr)
18,498✔
2946
{
2947
   switch (repr) {
18,498✔
2948
   case VCODE_REPR_U1:
2949
   case VCODE_REPR_U8:
2950
   case VCODE_REPR_U16:
2951
   case VCODE_REPR_U32:
2952
   case VCODE_REPR_U64: return 0;
2953
   case VCODE_REPR_I8:  return INT8_MIN;
2954
   case VCODE_REPR_I16: return INT16_MIN;
2955
   case VCODE_REPR_I32: return INT32_MIN;
2956
   case VCODE_REPR_I64: return INT64_MIN;
2957
   default:             return 0;
2958
   }
2959
}
2960

2961
static uint64_t vtype_repr_high(vtype_repr_t repr)
18,498✔
2962
{
2963
   switch (repr) {
18,498✔
2964
   case VCODE_REPR_U1:  return 1;
2965
   case VCODE_REPR_U8:  return UINT8_MAX;
2966
   case VCODE_REPR_U16: return UINT16_MAX;
2967
   case VCODE_REPR_U32: return UINT32_MAX;
2968
   case VCODE_REPR_U64: return UINT64_MAX;
2969
   case VCODE_REPR_I8:  return INT8_MAX;
2970
   case VCODE_REPR_I16: return INT16_MAX;
2971
   case VCODE_REPR_I32: return INT32_MAX;
2972
   case VCODE_REPR_I64: return INT64_MAX;
2973
   default:             return 0;
2974
   }
2975
}
2976

2977
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
18,498✔
2978
{
2979
   int64_t clamp_low = vtype_repr_low(repr);
18,498✔
2980
   uint64_t clamp_high = vtype_repr_high(repr);
18,498✔
2981

2982
   if (*low >= clamp_low && *high <= clamp_high)
18,498✔
2983
      return true;
2984
   else {
2985
      *low = MAX(clamp_low, *low);
8,896✔
2986
      *high = MIN(clamp_high, *high);
8,896✔
2987
      return false;
8,896✔
2988
   }
2989
}
2990

2991
static vcode_stamp_t vstamp_new(const vstamp_t *s)
1,098,158✔
2992
{
2993
   assert(active_unit != NULL);
1,098,158✔
2994

2995
   for (int i = 0; i < active_unit->stamps.count; i++) {
10,811,631✔
2996
      vstamp_t *cmp = &(active_unit->stamps.items[i]);
10,324,671✔
2997
      if (cmp->kind == s->kind && memcmp(&cmp->u, &s->u, sizeof(s->u)) == 0)
10,324,671✔
2998
         return MAKE_HANDLE(active_unit->depth, i);
611,198✔
2999
   }
3000

3001
   vstamp_t *new = vstamp_array_alloc(&(active_unit->stamps));
486,960✔
3002
   *new = *s;
486,960✔
3003

3004
   return MAKE_HANDLE(active_unit->depth, active_unit->stamps.count - 1);
486,960✔
3005
}
3006

3007
vcode_stamp_t vstamp_int(int64_t low, int64_t high)
1,042,536✔
3008
{
3009
   const vstamp_t s = {
1,042,536✔
3010
      .kind = VCODE_STAMP_INT,
3011
      .u = { .intg = { .low = low, .high = high } },
3012
   };
3013
   return vstamp_new(&s);
1,042,536✔
3014
}
3015

3016
vcode_stamp_t vstamp_real(double low, double high)
55,622✔
3017
{
3018
   const vstamp_t s = {
55,622✔
3019
      .kind = VCODE_STAMP_REAL,
3020
      .u = { .real = { .low = low, .high = high } },
3021
   };
3022
   return vstamp_new(&s);
55,622✔
3023
}
3024

3025
vcode_stamp_t vstamp_char(void)
8,549✔
3026
{
3027
   return vstamp_int(0, 255);
8,549✔
3028
}
3029

3030
int vcode_count_params(void)
27,609✔
3031
{
3032
   assert(active_unit != NULL);
27,609✔
3033
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
27,609✔
3034
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3035
          || active_unit->kind == VCODE_UNIT_PROPERTY
3036
          || active_unit->kind == VCODE_UNIT_PROTECTED
3037
          || active_unit->kind == VCODE_UNIT_PROCESS);
3038

3039
   return active_unit->params.count;
27,609✔
3040
}
3041

3042
vcode_type_t vcode_param_type(int param)
40,812✔
3043
{
3044
   assert(active_unit != NULL);
40,812✔
3045
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
40,812✔
3046
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3047
          || active_unit->kind == VCODE_UNIT_PROPERTY
3048
          || active_unit->kind == VCODE_UNIT_PROTECTED
3049
          || active_unit->kind == VCODE_UNIT_PROCESS);
3050
   assert(param < active_unit->params.count);
40,812✔
3051

3052
   return active_unit->params.items[param].type;
40,812✔
3053
}
3054

3055
ident_t vcode_param_name(int param)
40,812✔
3056
{
3057
   assert(active_unit != NULL);
40,812✔
3058
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
40,812✔
3059
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3060
          || active_unit->kind == VCODE_UNIT_PROPERTY
3061
          || active_unit->kind == VCODE_UNIT_PROTECTED
3062
          || active_unit->kind == VCODE_UNIT_PROCESS);
3063
   assert(param < active_unit->params.count);
40,812✔
3064

3065
   return active_unit->params.items[param].name;
40,812✔
3066
}
3067

3068
vcode_reg_t vcode_param_reg(int param)
40,812✔
3069
{
3070
   assert(active_unit != NULL);
40,812✔
3071
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
40,812✔
3072
          || active_unit->kind == VCODE_UNIT_PROCEDURE
3073
          || active_unit->kind == VCODE_UNIT_PROPERTY
3074
          || active_unit->kind == VCODE_UNIT_PROTECTED
3075
          || active_unit->kind == VCODE_UNIT_PROCESS);
3076
   assert(param < active_unit->params.count);
40,812✔
3077

3078
   return active_unit->params.items[param].reg;
40,812✔
3079
}
3080

3081
vcode_block_t emit_block(void)
191,633✔
3082
{
3083
   assert(active_unit != NULL);
191,633✔
3084

3085
   vcode_block_t bnum = active_unit->blocks.count;
191,633✔
3086

3087
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
191,633✔
3088
   memset(bptr, '\0', sizeof(block_t));
191,633✔
3089

3090
   if (active_block != VCODE_INVALID_BLOCK)
191,633✔
3091
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
116,845✔
3092
   else
3093
      bptr->last_loc = LOC_INVALID;
74,788✔
3094

3095
   return bnum;
191,633✔
3096
}
3097

3098
void vcode_select_unit(vcode_unit_t unit)
256,458✔
3099
{
3100
   active_unit  = unit;
256,458✔
3101
   active_block = VCODE_INVALID_BLOCK;
256,458✔
3102
}
256,458✔
3103

3104
void vcode_select_block(vcode_block_t block)
415,395✔
3105
{
3106
   assert(active_unit != NULL);
415,395✔
3107
   active_block = block;
415,395✔
3108
}
415,395✔
3109

3110
vcode_block_t vcode_active_block(void)
995✔
3111
{
3112
   assert(active_unit != NULL);
995✔
3113
   assert(active_block != -1);
995✔
3114
   return active_block;
995✔
3115
}
3116

3117
const loc_t *vcode_last_loc(void)
1,971,522✔
3118
{
3119
   return &(vcode_block_data()->last_loc);
1,971,522✔
3120
}
3121

3122
vcode_unit_t vcode_active_unit(void)
909✔
3123
{
3124
   assert(active_unit != NULL);
909✔
3125
   return active_unit;
909✔
3126
}
3127

3128
ident_t vcode_unit_name(vcode_unit_t vu)
215,053✔
3129
{
3130
   assert(vu != NULL);
215,053✔
3131
   return vu->name;
215,053✔
3132
}
3133

3134
bool vcode_unit_has_undefined(vcode_unit_t vu)
14,293✔
3135
{
3136
   assert(vu != NULL);
14,293✔
3137
   return !!(vu->flags & UNIT_UNDEFINED);
14,293✔
3138
}
3139

UNCOV
3140
int vcode_unit_depth(vcode_unit_t vu)
×
3141
{
UNCOV
3142
   assert(vu != NULL);
×
UNCOV
3143
   return vu->depth;
×
3144
}
3145

3146
void vcode_set_result(vcode_type_t type)
26,698✔
3147
{
3148
   assert(active_unit != NULL);
26,698✔
3149
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
26,698✔
3150
          || active_unit->kind == VCODE_UNIT_THUNK);
3151

3152
   active_unit->result = type;
26,698✔
3153
}
26,698✔
3154

3155
vcode_type_t vcode_unit_result(vcode_unit_t vu)
29,766✔
3156
{
3157
   assert(vu != NULL);
29,766✔
3158
   assert(vu->kind == VCODE_UNIT_FUNCTION || vu->kind == VCODE_UNIT_THUNK);
29,766✔
3159
   return vu->result;
29,766✔
3160
}
3161

3162
vunit_kind_t vcode_unit_kind(vcode_unit_t vu)
189,243✔
3163
{
3164
   assert(vu != NULL);
189,243✔
3165
   return vu->kind;
189,243✔
3166
}
3167

3168
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
81,545✔
3169
{
3170
   assert(vu != NULL);
81,545✔
3171
   return vu->context;
81,545✔
3172
}
3173

3174
object_t *vcode_unit_object(vcode_unit_t vu)
111,402✔
3175
{
3176
   assert(vu != NULL);
111,402✔
3177
   return vu->object;
111,402✔
3178
}
3179

3180
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
89,097✔
3181
{
3182
   int hops = 0;
89,097✔
3183
   for (; (unit = unit->context); hops++)
215,875✔
3184
      ;
3185
   return hops;
89,097✔
3186
}
3187

3188
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
38,423✔
3189
{
3190
   assert(context->kind != VCODE_UNIT_THUNK);
38,423✔
3191

3192
   child->next = NULL;
38,423✔
3193
   if (context->children == NULL)
38,423✔
3194
      context->children = child;
18,080✔
3195
   else {
3196
      vcode_unit_t it;
3197
      for (it = context->children; it->next != NULL; it = it->next)
90,541✔
3198
         ;
3199
      it->next = child;
20,343✔
3200
   }
3201
}
38,423✔
3202

3203
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
15,488✔
3204
{
3205
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
15,488✔
3206
   vu->kind     = VCODE_UNIT_FUNCTION;
15,488✔
3207
   vu->name     = name;
15,488✔
3208
   vu->context  = context;
15,488✔
3209
   vu->result   = VCODE_INVALID_TYPE;
15,488✔
3210
   vu->depth    = vcode_unit_calc_depth(vu);
15,488✔
3211
   vu->object   = obj;
15,488✔
3212

3213
   vcode_add_child(context, vu);
15,488✔
3214

3215
   vcode_select_unit(vu);
15,488✔
3216
   vcode_select_block(emit_block());
15,488✔
3217
   emit_debug_info(&(obj->loc));
15,488✔
3218

3219
   return vu;
15,488✔
3220
}
3221

3222
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
281✔
3223
{
3224
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
281✔
3225
   vu->kind     = VCODE_UNIT_PROCEDURE;
281✔
3226
   vu->name     = name;
281✔
3227
   vu->context  = context;
281✔
3228
   vu->result   = VCODE_INVALID_TYPE;
281✔
3229
   vu->depth    = vcode_unit_calc_depth(vu);
281✔
3230
   vu->object   = obj;
281✔
3231

3232
   vcode_add_child(context, vu);
281✔
3233

3234
   vcode_select_unit(vu);
281✔
3235
   vcode_select_block(emit_block());
281✔
3236
   emit_debug_info(&(obj->loc));
281✔
3237

3238
   return vu;
281✔
3239
}
3240

3241
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
10,494✔
3242
{
3243
   assert(context->kind == VCODE_UNIT_INSTANCE);
10,494✔
3244

3245
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
10,494✔
3246
   vu->kind     = VCODE_UNIT_PROCESS;
10,494✔
3247
   vu->name     = name;
10,494✔
3248
   vu->context  = context;
10,494✔
3249
   vu->depth    = vcode_unit_calc_depth(vu);
10,494✔
3250
   vu->result   = VCODE_INVALID_TYPE;
10,494✔
3251
   vu->object   = obj;
10,494✔
3252

3253
   vcode_add_child(context, vu);
10,494✔
3254

3255
   vcode_select_unit(vu);
10,494✔
3256
   vcode_select_block(emit_block());
10,494✔
3257
   emit_debug_info(&(obj->loc));
10,494✔
3258

3259
   return vu;
10,494✔
3260
}
3261

3262
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
16,706✔
3263
{
3264
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
16,706✔
3265

3266
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
16,706✔
3267
   vu->kind     = VCODE_UNIT_INSTANCE;
16,706✔
3268
   vu->name     = name;
16,706✔
3269
   vu->context  = context;
16,706✔
3270
   vu->depth    = vcode_unit_calc_depth(vu);
16,706✔
3271
   vu->result   = VCODE_INVALID_TYPE;
16,706✔
3272
   vu->object   = obj;
16,706✔
3273

3274
   if (context != NULL)
16,706✔
3275
      vcode_add_child(context, vu);
10,135✔
3276

3277
   vcode_select_unit(vu);
16,706✔
3278
   vcode_select_block(emit_block());
16,706✔
3279
   emit_debug_info(&(obj->loc));
16,706✔
3280

3281
   return vu;
16,706✔
3282
}
3283

3284
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
16,164✔
3285
{
3286
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
16,164✔
3287
   vu->kind     = VCODE_UNIT_PACKAGE;
16,164✔
3288
   vu->name     = name;
16,164✔
3289
   vu->context  = context;
16,164✔
3290
   vu->depth    = vcode_unit_calc_depth(vu);
16,164✔
3291
   vu->result   = VCODE_INVALID_TYPE;
16,164✔
3292
   vu->object   = obj;
16,164✔
3293

3294
   if (context != NULL)
16,164✔
3295
      vcode_add_child(context, vu);
309✔
3296

3297
   vcode_select_unit(vu);
16,164✔
3298
   vcode_select_block(emit_block());
16,164✔
3299
   emit_debug_info(&(obj->loc));
16,164✔
3300

3301
   return vu;
16,164✔
3302
}
3303

3304
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
1,022✔
3305
{
3306
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
1,022✔
3307
   vu->kind     = VCODE_UNIT_PROTECTED;
1,022✔
3308
   vu->name     = name;
1,022✔
3309
   vu->context  = context;
1,022✔
3310
   vu->depth    = vcode_unit_calc_depth(vu);
1,022✔
3311
   vu->result   = VCODE_INVALID_TYPE;
1,022✔
3312
   vu->object   = obj;
1,022✔
3313

3314
   if (context != NULL)
1,022✔
3315
      vcode_add_child(context, vu);
1,022✔
3316

3317
   vcode_select_unit(vu);
1,022✔
3318
   vcode_select_block(emit_block());
1,022✔
3319
   emit_debug_info(&(obj->loc));
1,022✔
3320

3321
   return vu;
1,022✔
3322
}
3323

3324
vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context)
324✔
3325
{
3326
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
324✔
3327
   vu->kind     = VCODE_UNIT_PROPERTY;
324✔
3328
   vu->name     = name;
324✔
3329
   vu->context  = context;
324✔
3330
   vu->depth    = vcode_unit_calc_depth(vu);
324✔
3331
   vu->result   = VCODE_INVALID_TYPE;
324✔
3332
   vu->object   = obj;
324✔
3333

3334
   if (context != NULL)
324✔
3335
      vcode_add_child(context, vu);
324✔
3336

3337
   vcode_select_unit(vu);
324✔
3338
   vcode_select_block(emit_block());
324✔
3339
   emit_debug_info(&(obj->loc));
324✔
3340

3341
   return vu;
324✔
3342
}
3343

3344
vcode_unit_t emit_thunk(ident_t name, object_t *obj, vcode_unit_t context)
14,309✔
3345
{
3346
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
14,309✔
3347
   vu->kind     = VCODE_UNIT_THUNK;
14,309✔
3348
   vu->name     = name;
14,309✔
3349
   vu->context  = context;
14,309✔
3350
   vu->depth    = vcode_unit_calc_depth(vu);
14,309✔
3351
   vu->result   = VCODE_INVALID_TYPE;
14,309✔
3352
   vu->depth    = vcode_unit_calc_depth(vu);
14,309✔
3353
   vu->object   = obj;
14,309✔
3354

3355
   if (context != NULL)
14,309✔
3356
      vcode_add_child(context, vu);
370✔
3357

3358
   vcode_select_unit(vu);
14,309✔
3359
   vcode_select_block(emit_block());
14,309✔
3360

3361
   return vu;
14,309✔
3362
}
3363

3364
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
19,473✔
3365
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3366
                 vcode_reg_t hint_right)
3367
{
3368
   int64_t value_const;
19,473✔
3369
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
19,473✔
3370
      emit_comment("Always true assertion on r%d", value);
40✔
3371
      return;
40✔
3372
   }
3373

3374
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
19,433✔
3375
   vcode_add_arg(op, value);
19,433✔
3376
   vcode_add_arg(op, severity);
19,433✔
3377
   vcode_add_arg(op, message);
19,433✔
3378
   vcode_add_arg(op, length);
19,433✔
3379
   vcode_add_arg(op, locus);
19,433✔
3380

3381
   if (hint_left != VCODE_INVALID_REG) {
19,433✔
3382
      vcode_add_arg(op, hint_left);
8,116✔
3383
      vcode_add_arg(op, hint_right);
8,116✔
3384

3385
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
8,116✔
3386
                   "left hint must be scalar");
3387
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
8,116✔
3388
                   "right hint must be scalar");
3389
   }
3390

3391
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
19,433✔
3392
                "value parameter to assert is not bool");
3393
   VCODE_ASSERT(message == VCODE_INVALID_REG
19,433✔
3394
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3395
                "message parameter to assert is not a pointer");
3396
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
19,433✔
3397
                "value parameter to assert is not bool");
3398
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
19,433✔
3399
                "locus argument to report must be a debug locus");
3400
}
3401

3402
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,803✔
3403
                 vcode_reg_t locus)
3404
{
3405
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,803✔
3406
   vcode_add_arg(op, severity);
2,803✔
3407
   vcode_add_arg(op, message);
2,803✔
3408
   vcode_add_arg(op, length);
2,803✔
3409
   vcode_add_arg(op, locus);
2,803✔
3410

3411
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,803✔
3412
                "message parameter to report is not a pointer");
3413
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,803✔
3414
                "message parameter to report is not a character pointer");
3415
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,803✔
3416
                "locus argument to report must be a debug locus");
3417
}
2,803✔
3418

3419
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
46,423✔
3420
{
3421
   if (lhs == rhs) {
46,423✔
3422
      if (cmp == VCODE_CMP_EQ)
521✔
3423
         return emit_const(vtype_bool(), 1);
309✔
3424
      else if (cmp == VCODE_CMP_NEQ)
212✔
UNCOV
3425
         return emit_const(vtype_bool(), 0);
×
3426
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
212✔
UNCOV
3427
         return emit_const(vtype_bool(), 1);
×
3428
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
212✔
3429
         return emit_const(vtype_bool(), 0);
212✔
3430
   }
3431

3432
   int64_t lconst, rconst;
45,902✔
3433
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
45,902✔
3434
      switch (cmp) {
432✔
3435
      case VCODE_CMP_EQ:
397✔
3436
         return emit_const(vtype_bool(), lconst == rconst);
397✔
3437
      case VCODE_CMP_NEQ:
4✔
3438
         return emit_const(vtype_bool(), lconst != rconst);
4✔
3439
      case VCODE_CMP_LT:
15✔
3440
         return emit_const(vtype_bool(), lconst < rconst);
15✔
3441
      case VCODE_CMP_GT:
16✔
3442
         return emit_const(vtype_bool(), lconst > rconst);
16✔
UNCOV
3443
      case VCODE_CMP_LEQ:
×
UNCOV
3444
         return emit_const(vtype_bool(), lconst <= rconst);
×
UNCOV
3445
      case VCODE_CMP_GEQ:
×
UNCOV
3446
         return emit_const(vtype_bool(), lconst >= rconst);
×
UNCOV
3447
      default:
×
3448
         fatal_trace("cannot fold comparison %d", cmp);
3449
      }
3450
   }
3451

3452
   // Reuse any previous operation in this block with the same arguments
3453
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
898,954✔
3454
      if (other->args.count == 2 && other->args.items[0] == lhs
33,135✔
3455
          && other->args.items[1] == rhs && other->cmp == cmp)
2,950✔
3456
         return other->result;
256✔
3457
   }
3458

3459
   op_t *op = vcode_add_op(VCODE_OP_CMP);
45,214✔
3460
   vcode_add_arg(op, lhs);
45,214✔
3461
   vcode_add_arg(op, rhs);
45,214✔
3462
   op->cmp    = cmp;
45,214✔
3463
   op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP);
45,214✔
3464

3465
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
45,214✔
3466
                "arguments to cmp are not the same type");
3467

3468
   return op->result;
45,214✔
3469
}
3470

3471
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_stamp_t stamp,
45,238✔
3472
                       const vcode_reg_t *args, int nargs)
3473
{
3474
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
45,238✔
3475
   o->func = func;
45,238✔
3476
   o->type = type;
45,238✔
3477
   for (int i = 0; i < nargs; i++)
159,701✔
3478
      vcode_add_arg(o, args[i]);
114,463✔
3479

3480
   for (int i = 0; i < nargs; i++)
159,701✔
3481
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
114,463✔
3482
                   "invalid argument to function");
3483

3484
   if (type == VCODE_INVALID_TYPE)
45,238✔
3485
      return (o->result = VCODE_INVALID_REG);
7,330✔
3486
   else
3487
      return (o->result = vcode_add_reg(type, stamp));
37,908✔
3488
}
3489

3490
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
1,143✔
3491
                vcode_block_t resume_bb)
3492
{
3493
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
1,143✔
3494
   o->func = func;
1,143✔
3495
   for (int i = 0; i < nargs; i++)
3,825✔
3496
      vcode_add_arg(o, args[i]);
2,682✔
3497

3498
   vcode_block_array_add(&(o->targets), resume_bb);
1,143✔
3499

3500
   for (int i = 0; i < nargs; i++)
3,825✔
3501
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,682✔
3502
                   "invalid argument to procedure");
3503

3504
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
1,143✔
3505
                "first argument to VHDL procedure must be context pointer");
3506
}
1,143✔
3507

3508
vcode_reg_t emit_alloc(vcode_type_t type, vcode_stamp_t stamp,
10,398✔
3509
                       vcode_reg_t count)
3510
{
3511
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
10,398✔
3512
   op->type = type;
10,398✔
3513
   vcode_add_arg(op, count);
10,398✔
3514

3515
   const vtype_kind_t tkind = vtype_kind(type);
10,398✔
3516
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
10,398✔
3517
                "alloca element type cannot be array");
3518
   VCODE_ASSERT(count != VCODE_INVALID_REG,
10,398✔
3519
                "alloca must have valid count argument");
3520

3521
   return (op->result = vcode_add_reg(vtype_pointer(type), stamp));
10,398✔
3522
}
3523

3524
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
2,376,763✔
3525
{
3526
   // Reuse any previous constant in this block with the same type and value
3527
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
56,737,011✔
3528
      if (other->value == value && vtype_eq(type, other->type))
19,480,677✔
3529
         return other->result;
1,736,458✔
3530
   }
3531

3532
   op_t *op = vcode_add_op(VCODE_OP_CONST);
640,305✔
3533
   op->value  = value;
640,305✔
3534
   op->type   = type;
640,305✔
3535
   op->result = vcode_add_reg(type, vstamp_int(value, value));
640,305✔
3536

3537
   vtype_kind_t type_kind = vtype_kind(type);
640,305✔
3538
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
640,305✔
3539
                "constant must have integer or offset type");
3540

3541
   return op->result;
3542
}
3543

3544
vcode_reg_t emit_const_real(vcode_type_t type, double value)
89,361✔
3545
{
3546
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
2,782,384✔
3547
      if (other->real == value && other->type == type)
1,179,086✔
3548
         return other->result;
35,023✔
3549
   }
3550

3551
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
54,338✔
3552
   op->real   = value;
54,338✔
3553
   op->type   = type;
54,338✔
3554
   op->result = vcode_add_reg(op->type, vstamp_real(value, value));
54,338✔
3555

3556
   return op->result;
54,338✔
3557
}
3558

3559
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
57,534✔
3560
{
3561
   vtype_kind_t kind = vtype_kind(type);
57,534✔
3562

3563
   // Reuse any previous operation in this block with the same arguments
3564
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
3,142,375✔
3565
      if (other->args.count != num)
225,530✔
3566
         continue;
133,693✔
3567
      else if (!vtype_eq(vcode_reg_type(other->result), type))
91,837✔
3568
         continue;
3,874✔
3569

3570
      bool match = true;
3571
      for (int i = 0; match && i < num; i++) {
680,987✔
3572
         if (other->args.items[i] != values[i])
593,024✔
3573
            match = false;
78,384✔
3574
      }
3575

3576
      if (match) return other->result;
87,963✔
3577
   }
3578

3579
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
47,955✔
3580
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
47,955✔
3581

3582
   for (int i = 0; i < num; i++)
2,855,944✔
3583
      vcode_add_arg(op, values[i]);
2,807,989✔
3584

3585
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
47,955✔
3586
                "constant array must have constrained array type");
3587
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
47,955✔
3588
                vtype_size(type), num);
3589

3590
#ifdef DEBUG
3591
   vcode_type_t elem = vtype_elem(type);
47,955✔
3592
   for (int i = 0; i < num; i++) {
2,855,944✔
3593
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
2,807,989✔
3594
                   "wrong element type for item %d", i);
3595
      vcode_assert_const(values[i], "array");
2,807,989✔
3596
   }
3597
#endif
3598

3599
   return op->result;
47,955✔
3600
}
3601

3602
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
634✔
3603
{
3604
   // Reuse any previous operation in this block with the same arguments
3605
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
11,837✔
3606
      if (other->args.items[0] == value && other->value == rep)
560✔
3607
         return other->result;
234✔
3608
   }
3609

3610
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
400✔
3611
   op->value = rep;
400✔
3612
   vcode_add_arg(op, value);
400✔
3613

3614
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
400✔
3615
                "constant array must have constrained array type");
3616
   VCODE_ASSERT(rep >= 0, "repeat count must be non-negative");
400✔
3617

3618
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
400✔
3619

3620
   return (op->result = vcode_add_reg(type, vcode_reg_data(value)->stamp));
400✔
3621
}
3622

3623
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
3,600✔
3624
{
3625
   // Reuse any previous constant in this block with the same type and value
3626
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
55,752✔
3627
      if (other->args.count == num && vtype_eq(type, other->type)) {
1,992✔
3628
         bool same_regs = true;
3629
         for (int i = 0; same_regs && i < num; i++)
3,451✔
3630
            same_regs = other->args.items[i] == values[i];
2,001✔
3631

3632
         if (same_regs)
1,450✔
3633
            return other->result;
251✔
3634
      }
3635
   }
3636

3637
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
3,349✔
3638
   op->type   = type;
3,349✔
3639
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
3,349✔
3640

3641
   for (int i = 0; i < num; i++)
11,826✔
3642
      vcode_add_arg(op, values[i]);
8,477✔
3643

3644
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
3,349✔
3645
                "constant record must have record type");
3646

3647
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
3,349✔
3648
                vtype_fields(type), num);
3649

3650
#ifdef DEBUG
3651
   for (int i = 0; i < num; i++) {
11,826✔
3652
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
8,477✔
3653
                   "wrong type for field %d", i);
3654
      vcode_assert_const(values[i], "record");
8,477✔
3655
   }
3656
#endif
3657

3658
   return op->result;
3,349✔
3659
}
3660

3661
vcode_reg_t emit_address_of(vcode_reg_t value)
59,940✔
3662
{
3663
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
3,257,755✔
3664
      if (other->args.items[0] == value)
227,116✔
3665
         return other->result;
9,597✔
3666
   }
3667

3668
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
50,343✔
3669
   vcode_add_arg(op, value);
50,343✔
3670

3671
   vcode_type_t vtype = vcode_reg_type(value);
50,343✔
3672

3673
   VCODE_ASSERT(vtype_is_composite(vtype),
50,343✔
3674
                "address of argument must be record or array");
3675

3676
   if (vtype_kind(vtype) == VCODE_TYPE_CARRAY) {
50,343✔
3677
      vcode_type_t elem = vtype_elem(vtype);
47,693✔
3678
      vcode_stamp_t stamp = vcode_reg_stamp(value);
47,693✔
3679
      return (op->result = vcode_add_reg(vtype_pointer(elem), stamp));
47,693✔
3680
   }
3681
   else {
3682
      vcode_stamp_t stamp = VCODE_INVALID_STAMP;
2,650✔
3683
      return (op->result = vcode_add_reg(vtype_pointer(vtype), stamp));
2,650✔
3684
   }
3685
}
3686

3687
void emit_wait(vcode_block_t target)
17,533✔
3688
{
3689
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
17,533✔
3690
   vcode_add_target(op, target);
17,533✔
3691
}
17,533✔
3692

3693
void emit_jump(vcode_block_t target)
48,363✔
3694
{
3695
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
48,363✔
3696
   vcode_add_target(op, target);
48,363✔
3697

3698
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
48,363✔
3699
}
48,363✔
3700

3701
vcode_var_t emit_var(vcode_type_t type, vcode_stamp_t stamp, ident_t name,
124,442✔
3702
                     vcode_var_flags_t flags)
3703
{
3704
   assert(active_unit != NULL);
124,442✔
3705

3706
   vcode_var_t var = active_unit->vars.count;
124,442✔
3707
   var_t *v = var_array_alloc(&(active_unit->vars));
124,442✔
3708
   memset(v, '\0', sizeof(var_t));
124,442✔
3709
   v->type  = type;
124,442✔
3710
   v->stamp = stamp;
124,442✔
3711
   v->name  = name;
124,442✔
3712
   v->flags = flags;
124,442✔
3713

3714
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
124,442✔
3715

3716
   return var;
124,442✔
3717
}
3718

3719
vcode_reg_t emit_param(vcode_type_t type, vcode_stamp_t stamp, ident_t name)
41,182✔
3720
{
3721
   assert(active_unit != NULL);
41,182✔
3722

3723
   param_t *p = param_array_alloc(&(active_unit->params));
41,182✔
3724
   memset(p, '\0', sizeof(param_t));
41,182✔
3725
   p->type  = type;
41,182✔
3726
   p->stamp = stamp;
41,182✔
3727
   p->name  = name;
41,182✔
3728
   p->reg   = vcode_add_reg(type, stamp);
41,182✔
3729

3730
   assert(stamp == VCODE_INVALID_STAMP || vcode_stamp_data(stamp));
41,182✔
3731

3732
   return p->reg;
41,182✔
3733
}
3734

3735
vcode_reg_t emit_load(vcode_var_t var)
77,483✔
3736
{
3737
   // Try scanning backwards through the block for another load or store to
3738
   // this variable
3739
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
77,483✔
3740
   vcode_reg_t fold = VCODE_INVALID_REG;
77,483✔
3741
   VCODE_FOR_EACH_OP(other) {
1,275,661✔
3742
      switch (state) {
1,217,075✔
3743
      case EAGER:
491,184✔
3744
         if (other->kind == VCODE_OP_LOAD && other->address == var)
491,184✔
3745
            return other->result;
5,010✔
3746
         else if (other->kind == VCODE_OP_STORE && other->address == var)
486,174✔
3747
            return other->args.items[0];
13,887✔
3748
         else if (other->kind == VCODE_OP_FCALL
472,287✔
3749
                  || other->kind == VCODE_OP_PCALL
472,287✔
3750
                  || other->kind == VCODE_OP_FILE_READ
3751
                  || other->kind == VCODE_OP_FILE_OPEN
3752
                  || other->kind == VCODE_OP_STORE_INDIRECT
3753
                  || other->kind == VCODE_OP_DEALLOCATE)
3754
            state = CONSERVATIVE;   // May write to variable
13,388✔
3755
         break;
3756

3757
      case CONSERVATIVE:
682,876✔
3758
         if (other->kind == VCODE_OP_LOAD && other->address == var
682,876✔
3759
             && fold == VCODE_INVALID_REG)
5,844✔
3760
            fold = other->result;
4,645✔
3761
         else if (other->kind == VCODE_OP_STORE && other->address == var
678,231✔
3762
                  && fold == VCODE_INVALID_REG)
3,706✔
3763
            fold = other->args.items[0];
3,490✔
3764
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
674,741✔
3765
            state = UNSAFE;
3766
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
672,802✔
3767
            state = UNSAFE;   // Nested call captures variables
180✔
3768
         break;
3769

3770
      case UNSAFE:
3771
         break;
3772
      }
3773
   }
3774

3775
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
58,586✔
3776
      return fold;
3777

3778
   var_t *v = vcode_var_data(var);
50,980✔
3779

3780
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
50,980✔
3781
   op->address = var;
50,980✔
3782
   op->result  = vcode_add_reg(v->type, v->stamp);
50,980✔
3783

3784
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
50,980✔
3785

3786
   return op->result;
3787
}
3788

3789
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
133,118✔
3790
{
3791
   VCODE_FOR_EACH_OP(other) {
1,608,236✔
3792
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,520,680✔
3793
          && other->args.items[0] == reg) {
224,422✔
3794
         return other->result;
15,266✔
3795
      }
3796
      else if (other->kind == VCODE_OP_FCALL
1,505,414✔
3797
               || other->kind == VCODE_OP_PCALL
1,505,414✔
3798
               || other->kind == VCODE_OP_STORE
3799
               || other->kind == VCODE_OP_STORE_INDIRECT
3800
               || other->kind == VCODE_OP_MEMSET
3801
               || other->kind == VCODE_OP_COPY
3802
               || other->kind == VCODE_OP_FILE_READ)
3803
         break;   // May write to this pointer
3804
   }
3805

3806
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
117,852✔
3807
   vcode_add_arg(op, reg);
117,852✔
3808

3809
   vcode_type_t rtype = vcode_reg_type(reg);
117,852✔
3810

3811
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
117,852✔
3812
                "load indirect with non-pointer argument");
3813

3814
   vcode_type_t deref = vtype_pointed(rtype);
117,852✔
3815
   op->result = vcode_add_reg(deref, vcode_reg_stamp(reg));
117,852✔
3816

3817
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
117,852✔
3818

3819
   return op->result;
3820
}
3821

3822
void emit_store(vcode_reg_t reg, vcode_var_t var)
124,226✔
3823
{
3824
   // Any previous store to this variable in this block is dead
3825
   VCODE_FOR_EACH_OP(other) {
2,670,678✔
3826
      if (other->kind == VCODE_OP_STORE && other->address == var) {
2,566,265✔
3827
         other->kind = VCODE_OP_COMMENT;
384✔
3828
         other->comment =
768✔
3829
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
384✔
3830
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
384✔
3831
      }
3832
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
2,565,881✔
3833
         break;   // Needs to get variable for display
3834
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
2,557,307✔
3835
               && other->address == var)
56,998✔
3836
         break;   // Previous value may be used
3837
   }
3838

3839
   var_t *v = vcode_var_data(var);
124,226✔
3840
   reg_t *r = vcode_reg_data(reg);
124,226✔
3841

3842
   op_t *op = vcode_add_op(VCODE_OP_STORE);
124,226✔
3843
   vcode_add_arg(op, reg);
124,226✔
3844
   op->address = var;
124,226✔
3845

3846
   VCODE_ASSERT(vtype_eq(v->type, r->type),
124,226✔
3847
                "variable and stored value do not have same type");
3848
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
124,226✔
3849
}
124,226✔
3850

3851
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
22,242✔
3852
{
3853
   reg_t *p = vcode_reg_data(ptr);
22,242✔
3854
   reg_t *r = vcode_reg_data(reg);
22,242✔
3855

3856
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
22,242✔
3857
   vcode_add_arg(op, reg);
22,242✔
3858
   vcode_add_arg(op, ptr);
22,242✔
3859

3860
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
22,242✔
3861
                "store indirect target is not a pointer");
3862
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
22,242✔
3863
                "pointer and stored value do not have same type");
3864
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
22,242✔
3865
}
22,242✔
3866

3867
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
90,477✔
3868
                              vcode_reg_t locus)
3869
{
3870
   // Reuse any previous operation in this block with the same arguments
3871
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
2,251,412✔
3872
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
118,059✔
3873
         return other->result;
8,294✔
3874
   }
3875

3876
   op_t *op = vcode_add_op(kind);
82,183✔
3877
   vcode_add_arg(op, lhs);
82,183✔
3878
   vcode_add_arg(op, rhs);
82,183✔
3879
   if (locus != VCODE_INVALID_REG)
82,183✔
3880
      vcode_add_arg(op, locus);
9,681✔
3881

3882
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
82,183✔
3883

3884
   vcode_type_t lhs_type = vcode_reg_type(lhs);
82,183✔
3885
   vcode_type_t rhs_type = vcode_reg_type(rhs);
82,183✔
3886

3887
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
82,183✔
3888
                "arguments to %s are not the same type", vcode_op_string(kind));
3889

3890
   return op->result;
82,183✔
3891
}
3892

3893
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
70,505✔
3894
                               vcode_reg_t locus)
3895
{
3896
   int64_t lconst, rconst;
70,505✔
3897
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
70,505✔
3898
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
70,505✔
3899
   if (l_is_const && r_is_const)
70,505✔
3900
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
34,478✔
3901
   else if (r_is_const && rconst == 1)
36,027✔
3902
      return lhs;
3903
   else if (l_is_const && lconst == 1)
6,780✔
3904
      return rhs;
3905
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
6,076✔
3906
      return emit_const(vcode_reg_type(lhs), 0);
79✔
3907

3908
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
5,997✔
3909

3910
   double rl_low, rl_high, rr_low, rr_high;
5,997✔
3911
   int64_t l_low, l_high, r_low, r_high;
5,997✔
3912

3913
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
5,997✔
3914
       && vcode_reg_bounds(rhs, &r_low, &r_high)) {
5,290✔
3915
      const int64_t ll = smul64(l_low, r_low);
5,290✔
3916
      const int64_t lh = smul64(l_low, r_high);
5,290✔
3917
      const int64_t hl = smul64(l_high, r_low);
5,290✔
3918
      const int64_t hh = smul64(l_high, r_high);
5,290✔
3919

3920
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
5,290✔
3921
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
5,290✔
3922

3923
      if (min > INT64_MIN && max < INT64_MAX) {
5,290✔
3924
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
2,953✔
3925
         if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
2,953✔
3926
            op = VCODE_OP_MUL;   // Cannot overflow
945✔
3927
            locus = VCODE_INVALID_REG;
945✔
3928
         }
3929
      }
3930

3931
      vstamp = vstamp_int(min, max);
5,290✔
3932
   }
3933
   else if (vcode_reg_bounds_real(lhs, &rl_low, &rl_high)
707✔
3934
            && vcode_reg_bounds_real(rhs, &rr_low, &rr_high)) {
707✔
3935
      const double ll = rl_low * rr_low;
707✔
3936
      const double lh = rl_low * rr_high;
707✔
3937
      const double hl = rl_high * rr_low;
707✔
3938
      const double hh = rl_high * rr_high;
707✔
3939

3940
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,641✔
3941
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,761✔
3942

3943
      vstamp = vstamp_real(min, max);
707✔
3944
   }
3945

3946
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
5,997✔
3947

3948
   if (vstamp != VCODE_INVALID_TYPE)
5,997✔
3949
      vcode_reg_data(reg)->stamp = vstamp;
5,997✔
3950

3951
   return reg;
3952
}
3953

3954
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
66,221✔
3955
{
3956
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
66,221✔
3957
}
3958

3959
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
4,284✔
3960
{
3961
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
4,284✔
3962

3963
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
4,284✔
3964
                "trapping add may only be used with integer types");
3965

3966
   return result;
4,284✔
3967
}
3968

3969
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
2,438✔
3970
{
3971
   int64_t lconst, rconst;
2,438✔
3972
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
2,438✔
3973
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
2,438✔
3974
   if (l_is_const && r_is_const && rconst != 0)
2,438✔
3975
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
39✔
3976
   else if (r_is_const && rconst == 1)
2,399✔
3977
      return lhs;
3978

3979
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
2,395✔
3980

3981
   int64_t l_low, l_high;
2,395✔
3982
   if (vcode_reg_bounds(lhs, &l_low, &l_high)) {
2,395✔
3983
      if (r_is_const && rconst != 0) {
1,975✔
3984
         reg_t *rr = vcode_reg_data(reg);
1,879✔
3985
         rr->stamp = vstamp_int(l_low / rconst, l_high / rconst);
1,879✔
3986
      }
3987
   }
3988
   else {
3989
      reg_t *rr = vcode_reg_data(reg);
420✔
3990
      rr->stamp = vstamp_real(-INFINITY, INFINITY);
420✔
3991
   }
3992

3993
   return reg;
3994
}
3995

3996
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
191✔
3997
{
3998
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
191✔
3999
}
4000

4001
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
233✔
4002
{
4003
   int64_t rconst;
233✔
4004
   if (vcode_reg_const(rhs, &rconst)) {
233✔
4005
      if (rconst == 0)
113✔
4006
         return emit_const(vcode_reg_type(lhs), 1);
51✔
4007
      else if (rconst == 1)
62✔
4008
         return lhs;
4009
   }
4010

4011
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
181✔
4012

4013
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
181✔
4014
                "trapping exp may only be used with integer types");
4015

4016
   return result;
4017
}
4018

4019
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
256✔
4020
{
4021
   int64_t lconst, rconst;
256✔
4022
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
256✔
4023
       && lconst > 0 && rconst > 0)
19✔
4024
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
4✔
4025

4026
   int64_t l_low, l_high, r_low, r_high;
252✔
4027
   if (vcode_reg_bounds(lhs, &l_low, &l_high) && l_low >= 0
252✔
4028
       && vcode_reg_bounds(rhs, &r_low, &r_high) && r_low >= 0) {
113✔
4029
      // If both arguments are non-negative then rem is equivalent and
4030
      // cheaper to compute
4031
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
108✔
4032

4033
      reg_t *rr = vcode_reg_data(reg);
108✔
4034
      rr->stamp = vstamp_int(0, MAX(0, r_high - 1));
108✔
4035

4036
      return reg;
108✔
4037
   }
4038
   else
4039
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
144✔
4040
}
4041

4042
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
1,214✔
4043
{
4044
   int64_t lconst, rconst;
1,214✔
4045
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
1,214✔
4046
       && lconst > 0 && rconst > 0)
2✔
UNCOV
4047
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
4048

4049
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
1,214✔
4050

4051
   int64_t l_low, l_high, r_low, r_high;
1,214✔
4052
   if (vcode_reg_bounds(lhs, &l_low, &l_high) && l_low >= 0
1,214✔
4053
       && vcode_reg_bounds(rhs, &r_low, &r_high) && r_low >= 0) {
709✔
4054
      reg_t *rr = vcode_reg_data(reg);
704✔
4055
      rr->stamp = vstamp_int(0, r_high - 1);
704✔
4056
   }
4057

4058
   return reg;
4059
}
4060

4061
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
66,503✔
4062
                               vcode_reg_t locus)
4063
{
4064
   int64_t lconst, rconst;
66,503✔
4065
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
66,503✔
4066
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
66,503✔
4067
   if (l_is_const && r_is_const)
66,503✔
4068
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
16,833✔
4069
   else if (r_is_const && rconst == 0)
49,670✔
4070
      return lhs;
4071
   else if (l_is_const && lconst == 0)
49,495✔
4072
      return rhs;
4073

4074
   int64_t l_low, l_high, r_low, r_high;
28,214✔
4075
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
28,214✔
4076
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
28,214✔
4077
       && vcode_reg_bounds(rhs, &r_low, &r_high))  {
27,796✔
4078

4079
      int64_t rbl = sadd64(l_low, r_low);
27,796✔
4080
      int64_t rbh = sadd64(l_high, r_high);
27,796✔
4081

4082
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
27,796✔
4083
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
14,547✔
4084
         if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
14,547✔
4085
            op = VCODE_OP_ADD;   // Cannot overflow
1,909✔
4086
            locus = VCODE_INVALID_REG;
1,909✔
4087
         }
4088
      }
4089

4090
      vstamp = vstamp_int(rbl, rbh);
27,796✔
4091
   }
4092

4093
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
28,214✔
4094

4095
   if (vstamp != VCODE_INVALID_STAMP)
28,214✔
4096
      vcode_reg_data(reg)->stamp = vstamp;
27,796✔
4097

4098
   return reg;
4099
}
4100

4101
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
57,782✔
4102
{
4103
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
57,782✔
4104
}
4105

4106
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
8,721✔
4107
{
4108
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
8,721✔
4109

4110
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
8,721✔
4111
                "trapping add may only be used with integer types");
4112

4113
   return result;
8,721✔
4114
}
4115

4116
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
62,251✔
4117
                               vcode_reg_t locus)
4118
{
4119
   int64_t lconst, rconst;
62,251✔
4120
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
62,251✔
4121
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
62,251✔
4122
   if (l_is_const && r_is_const)
62,251✔
4123
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
11,653✔
4124
   else if (r_is_const && rconst == 0)
50,598✔
4125
      return lhs;
4126
   else if (l_is_const && lconst == 0)
43,940✔
4127
      return emit_neg(rhs);
1,159✔
4128

4129
   int64_t l_low, l_high, r_low, r_high;
42,781✔
4130
   vcode_stamp_t vstamp = VCODE_INVALID_STAMP;
42,781✔
4131
   if (vcode_reg_bounds(lhs, &l_low, &l_high)
42,781✔
4132
       && vcode_reg_bounds(rhs, &r_low, &r_high))  {
42,405✔
4133

4134
      int64_t rbl = ssub64(l_low, r_high);
42,405✔
4135
      int64_t rbh = ssub64(l_high, r_low);
42,405✔
4136

4137
      if (rbl > INT64_MIN && rbh < INT64_MAX) {
42,405✔
4138
         vtype_repr_t repr = vtype_repr(vcode_reg_data(lhs)->type);
39,888✔
4139
         if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
39,888✔
4140
            op = VCODE_OP_SUB;   // Cannot overflow
6,748✔
4141
            locus = VCODE_INVALID_REG;
6,748✔
4142
         }
4143
      }
4144

4145
      vstamp = vstamp_int(rbl, rbh);
42,405✔
4146
   }
4147

4148
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
42,781✔
4149

4150
   if (vstamp != VCODE_INVALID_TYPE)
42,781✔
4151
      vcode_reg_data(reg)->stamp = vstamp;
42,405✔
4152

4153
   return reg;
4154
}
4155

4156
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
52,866✔
4157
{
4158
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
52,866✔
4159
}
4160

4161
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
9,385✔
4162
{
4163
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
9,385✔
4164

4165
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
9,385✔
4166
                "trapping sub may only be used with integer types");
4167

4168
   return result;
9,385✔
4169
}
4170

4171
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
106,308✔
4172
{
4173
   switch (vtype_kind(var->type)) {
106,308✔
4174
   case VCODE_TYPE_CARRAY:
35,949✔
4175
      op->type = vtype_pointer(vtype_elem(var->type));
35,949✔
4176
      op->result = vcode_add_reg(op->type, var->stamp);
35,949✔
4177
      break;
35,949✔
4178

4179
   case VCODE_TYPE_RECORD:
8,474✔
4180
      op->type = vtype_pointer(var->type);
8,474✔
4181
      op->result = vcode_add_reg(op->type, VCODE_INVALID_STAMP);
8,474✔
4182
      break;
8,474✔
4183

4184
   case VCODE_TYPE_INT:
61,885✔
4185
   case VCODE_TYPE_FILE:
4186
   case VCODE_TYPE_ACCESS:
4187
   case VCODE_TYPE_REAL:
4188
   case VCODE_TYPE_UARRAY:
4189
   case VCODE_TYPE_POINTER:
4190
   case VCODE_TYPE_SIGNAL:
4191
   case VCODE_TYPE_CONTEXT:
4192
   case VCODE_TYPE_OFFSET:
4193
   case VCODE_TYPE_TRIGGER:
4194
   case VCODE_TYPE_RESOLUTION:
4195
      op->type = vtype_pointer(var->type);
61,885✔
4196
      op->result = vcode_add_reg(op->type, var->stamp);
61,885✔
4197
      break;
61,885✔
4198

4199
   default:
UNCOV
4200
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4201
                   istr(var->name));
4202
   }
4203
}
106,308✔
4204

4205
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
54,787✔
4206
{
4207
   // Try to find a previous index of this var by this offset
4208
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
2,479,457✔
4209
      if (other->address == var
144,950✔
4210
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
10,336✔
UNCOV
4211
              || (offset != VCODE_INVALID_REG
×
UNCOV
4212
                  && other->args.items[0] == offset)))
×
4213
         return other->result;
10,336✔
4214
   }
4215

4216
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
44,451✔
4217
   op->address = var;
44,451✔
4218

4219
   if (offset != VCODE_INVALID_REG)
44,451✔
UNCOV
4220
      vcode_add_arg(op, offset);
×
4221

4222
   vcode_calculate_var_index_type(op, vcode_var_data(var));
44,451✔
4223

4224
   if (offset != VCODE_INVALID_REG)
44,451✔
UNCOV
4225
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4226
                   "index offset r%d does not have offset type", offset);
4227

4228
   return op->result;
44,451✔
4229
}
4230

4231
vcode_reg_t emit_cast(vcode_type_t type, vcode_stamp_t stamp, vcode_reg_t reg)
348,293✔
4232
{
4233
   if (vtype_eq(vcode_reg_type(reg), type))
348,293✔
4234
      return reg;
348,293✔
4235

4236
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
111,125✔
4237
   vtype_kind_t to   = vtype_kind(type);
111,125✔
4238

4239
   const bool integral =
222,250✔
4240
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
111,125✔
4241
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
111,125✔
4242

4243
   int64_t value;
111,125✔
4244
   if (integral && vcode_reg_const(reg, &value))
111,125✔
4245
      return emit_const(type, value);
17,812✔
4246

4247
   // Try to find a previous cast of this register to this type
4248
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,931,616✔
4249
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
200,951✔
4250
         return other->result;
21,525✔
4251
   }
4252

4253
   op_t *op = vcode_add_op(VCODE_OP_CAST);
71,788✔
4254
   vcode_add_arg(op, reg);
71,788✔
4255
   op->type  = type;
71,788✔
4256

4257
   static const vcode_type_t allowed[][2] = {
71,788✔
4258
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4259
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4260
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4261
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4262
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4263
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4264
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4265
   };
4266

4267
   if (integral) {
71,788✔
4268
      vtype_t *vt = vcode_type_data(type);
70,621✔
4269
      int64_t low = vt->low, high = vt->high;
70,621✔
4270

4271
      vstamp_t *rt = vcode_stamp_data(vcode_reg_data(reg)->stamp);
70,621✔
4272
      if (rt != NULL) {
70,621✔
4273
         VCODE_ASSERT(rt->kind == VCODE_STAMP_INT, "must be integer stamp");
17,369✔
4274
         low = MAX(low, rt->u.intg.low);
17,369✔
4275
         high = MIN(high, rt->u.intg.high);
17,369✔
4276
      }
4277

4278
      vstamp_t *bt = vcode_stamp_data(stamp);
70,621✔
4279
      if (bt != NULL) {
70,621✔
4280
         VCODE_ASSERT(bt->kind == VCODE_STAMP_INT, "must be integer stamp");
29,757✔
4281
         low = MAX(low, bt->u.intg.low);
29,757✔
4282
         high = MIN(high, bt->u.intg.high);
29,757✔
4283
      }
4284

4285
      stamp = vstamp_int(low, high);
70,621✔
4286
   }
4287

4288
   op->result = vcode_add_reg(type, stamp);
71,788✔
4289

4290
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
126,861✔
4291
      if (from == allowed[i][0] && to == allowed[i][1])
126,861✔
4292
         return op->result;
4293
   }
4294

UNCOV
4295
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4296
}
4297

4298
void emit_return(vcode_reg_t reg)
80,413✔
4299
{
4300
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
80,413✔
4301
   if (reg != VCODE_INVALID_REG) {
80,413✔
4302
      vcode_add_arg(op, reg);
30,998✔
4303

4304
      const vtype_kind_t rkind = vcode_reg_kind(reg);
30,998✔
4305
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY)
30,998✔
4306
         vcode_heap_allocate(reg);
5,719✔
4307

4308
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
30,998✔
4309
                   || active_unit->kind == VCODE_UNIT_THUNK
4310
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4311
                   "returning value fron non-function unit");
4312
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
30,998✔
4313
                    && rkind == VCODE_TYPE_INT)
4314
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4315
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4316
                       && rkind == VCODE_TYPE_ACCESS),
4317
                   "return value incorrect type");
4318
   }
4319
}
80,413✔
4320

4321
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
12,261✔
4322
                         vcode_reg_t values, vcode_reg_t reject,
4323
                         vcode_reg_t after)
4324
{
4325
   int64_t nconst;
12,261✔
4326
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
12,261✔
4327
      emit_comment("Skip empty waveform");
12✔
4328
      return;
12✔
4329
   }
4330

4331
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
12,249✔
4332
   vcode_add_arg(op, nets);
12,249✔
4333
   vcode_add_arg(op, nnets);
12,249✔
4334
   vcode_add_arg(op, values);
12,249✔
4335
   vcode_add_arg(op, reject);
12,249✔
4336
   vcode_add_arg(op, after);
12,249✔
4337

4338
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
12,249✔
4339
                "sched_waveform target is not signal");
4340
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
12,249✔
4341
                "sched_waveform net count is not offset type");
4342
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
12,249✔
4343
                "signal cannot be values argument for sched_waveform");
4344
}
4345

4346
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
93✔
4347
{
4348
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
93✔
4349
   vcode_add_arg(op, nets);
93✔
4350
   vcode_add_arg(op, nnets);
93✔
4351
   vcode_add_arg(op, values);
93✔
4352

4353
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
93✔
4354
                "force target is not signal");
4355
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
93✔
4356
                "force net count is not offset type");
4357
}
93✔
4358

4359
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
56✔
4360
{
4361
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
56✔
4362
   vcode_add_arg(op, nets);
56✔
4363
   vcode_add_arg(op, nnets);
56✔
4364

4365
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
56✔
4366
                "release target is not signal");
4367
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
56✔
4368
                "release net count is not offset type");
4369
}
56✔
4370

4371
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
32✔
4372
                     vcode_reg_t after)
4373
{
4374
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
32✔
4375
   vcode_add_arg(op, nets);
32✔
4376
   vcode_add_arg(op, nnets);
32✔
4377
   vcode_add_arg(op, reject);
32✔
4378
   vcode_add_arg(op, after);
32✔
4379

4380
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
32✔
4381
                "disconnect target is not signal");
4382
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
32✔
4383
                "disconnect net count is not offset type");
4384
}
32✔
4385

4386
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
44,073✔
4387
{
4388
   int64_t tconst;
44,073✔
4389
   if (vcode_reg_const(test, &tconst)) {
44,073✔
4390
      emit_jump(!!tconst ? btrue : bfalse);
5,319✔
4391
      return;
2,712✔
4392
   }
4393

4394
   op_t *op = vcode_add_op(VCODE_OP_COND);
41,361✔
4395
   vcode_add_arg(op, test);
41,361✔
4396
   vcode_add_target(op, btrue);
41,361✔
4397
   vcode_add_target(op, bfalse);
41,361✔
4398

4399
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
41,361✔
4400
                "cond test is not a bool");
4401
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
41,361✔
4402
                "invalid cond targets");
4403
}
4404

4405
vcode_reg_t emit_neg(vcode_reg_t lhs)
8,750✔
4406
{
4407
   int64_t lconst;
8,750✔
4408
   if (vcode_reg_const(lhs, &lconst))
8,750✔
UNCOV
4409
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4410

4411
   op_t *op = vcode_add_op(VCODE_OP_NEG);
8,750✔
4412
   vcode_add_arg(op, lhs);
8,750✔
4413
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
8,750✔
4414

4415
   return op->result;
8,750✔
4416
}
4417

4418
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
594✔
4419
{
4420
   int64_t lconst;
594✔
4421
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
594✔
UNCOV
4422
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4423

4424
   reg_t *lhs_r = vcode_reg_data(lhs);
594✔
4425

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

4430
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
337✔
4431
   vcode_add_arg(op, lhs);
337✔
4432
   vcode_add_arg(op, locus);
337✔
4433

4434
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
337✔
4435
                "locus argument to trap neg must be a debug locus");
4436
   VCODE_ASSERT(vtype_kind(lhs_r->type) == VCODE_TYPE_INT,
337✔
4437
                "trapping neg may only be used with integer types");
4438

4439
   return (op->result = vcode_add_reg(lhs_r->type, VCODE_INVALID_STAMP));
337✔
4440
}
4441

4442
vcode_reg_t emit_abs(vcode_reg_t lhs)
894✔
4443
{
4444
   int64_t lconst;
894✔
4445
   if (vcode_reg_const(lhs, &lconst))
894✔
4446
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4447

4448
   op_t *op = vcode_add_op(VCODE_OP_ABS);
893✔
4449
   vcode_add_arg(op, lhs);
893✔
4450
   op->result = vcode_add_reg(vcode_reg_type(lhs), VCODE_INVALID_STAMP);
893✔
4451

4452
   return op->result;
893✔
4453
}
4454

4455
void emit_comment(const char *fmt, ...)
124,756✔
4456
{
4457
#ifndef NDEBUG
4458
   va_list ap;
124,756✔
4459
   va_start(ap, fmt);
124,756✔
4460

4461
   char *buf = xvasprintf(fmt, ap);
124,756✔
4462
   for (char *p = buf + strlen(buf) - 1;
124,756✔
4463
        p >= buf && isspace_iso88591(*p); p--)
124,756✔
UNCOV
4464
      *p = '\0';
×
4465

4466
   vcode_add_op(VCODE_OP_COMMENT)->comment = buf;
124,756✔
4467
   va_end(ap);
124,756✔
4468
#endif
4469
}
124,756✔
4470

4471
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
25,094✔
4472
                        vcode_reg_t rfalse)
4473
{
4474
   int64_t tconst;
25,094✔
4475
   if (vcode_reg_const(test, &tconst))
25,094✔
4476
      return !!tconst ? rtrue : rfalse;
6,434✔
4477
   else if (rtrue == rfalse)
18,660✔
4478
      return rtrue;
4479

4480
   // Find a previous identical select
4481
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
415,415✔
4482
      if (other->args.items[0] == test && other->args.items[1] == rtrue
16,141✔
4483
          && other->args.items[2] == rfalse)
837✔
4484
         return other->result;
704✔
4485
   }
4486

4487
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
17,725✔
4488
   vcode_add_arg(op, test);
17,725✔
4489
   vcode_add_arg(op, rtrue);
17,725✔
4490
   vcode_add_arg(op, rfalse);
17,725✔
4491
   op->result = vcode_add_reg(vcode_reg_type(rtrue), VCODE_INVALID_STAMP);
17,725✔
4492

4493
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
17,725✔
4494
                "select test must have bool type");
4495
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
17,725✔
4496
                "select arguments are not the same type");
4497

4498
   return op->result;
17,725✔
4499
}
4500

4501
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
589✔
4502
{
4503
   switch (op) {
589✔
4504
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
60✔
4505
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
465✔
4506
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
16✔
4507
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
16✔
4508
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
16✔
4509
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
16✔
UNCOV
4510
   default:
×
4511
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
4512
   }
4513
}
4514

4515
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
9,885✔
4516
{
4517
   vcode_type_t vtbool = vtype_bool();
9,885✔
4518

4519
   int64_t lconst, rconst;
9,885✔
4520
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
9,885✔
4521
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
9,885✔
4522
   if (l_is_const && r_is_const) {
9,885✔
4523
      switch (op) {
8✔
UNCOV
4524
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
UNCOV
4525
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
UNCOV
4526
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
×
4527
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
8✔
UNCOV
4528
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
UNCOV
4529
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
UNCOV
4530
      default:
×
4531
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4532
      }
4533
   }
4534
   else if (l_is_const)
9,877✔
4535
      return emit_logical_identity(op, rhs, !!lconst);
456✔
4536
   else if (r_is_const)
9,421✔
4537
      return emit_logical_identity(op, lhs, !!rconst);
133✔
4538
   else if (lhs == rhs) {
9,288✔
4539
      switch (op) {
36✔
4540
      case VCODE_OP_AND:
4541
      case VCODE_OP_OR:
4542
         return lhs;
4543
      case VCODE_OP_NAND:
8✔
4544
      case VCODE_OP_NOR:
4545
         return emit_not(lhs);
8✔
4546
      case VCODE_OP_XOR:
4✔
4547
         return emit_const(vtbool, 0);
4✔
UNCOV
4548
      case VCODE_OP_XNOR:
×
UNCOV
4549
         return emit_const(vtbool, 1);
×
UNCOV
4550
      default:
×
4551
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4552
      }
4553
   }
4554

4555
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
9,252✔
4556

4557
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
9,252✔
4558
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4559
                "arguments to %s are not boolean", vcode_op_string(op));
4560

4561
   return result;
4562
}
4563

4564
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
3,170✔
4565
{
4566
   return emit_logical(VCODE_OP_OR, lhs, rhs);
3,170✔
4567
}
4568

4569
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
6,419✔
4570
{
4571
   return emit_logical(VCODE_OP_AND, lhs, rhs);
6,419✔
4572
}
4573

4574
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
65✔
4575
{
4576
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
65✔
4577
}
4578

4579
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
66✔
4580
{
4581
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
66✔
4582
}
4583

4584
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
92✔
4585
{
4586
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
92✔
4587
}
4588

4589
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
73✔
4590
{
4591
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
73✔
4592
}
4593

4594
vcode_reg_t emit_not(vcode_reg_t arg)
3,447✔
4595
{
4596
   int64_t cval;
3,447✔
4597
   if (vcode_reg_const(arg, &cval))
3,447✔
4598
      return emit_const(vtype_bool(), !cval);
36✔
4599

4600
   op_t *op = vcode_add_op(VCODE_OP_NOT);
3,411✔
4601
   vcode_add_arg(op, arg);
3,411✔
4602

4603
   vcode_type_t vtbool = vtype_bool();
3,411✔
4604
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
3,411✔
4605
                "argument to not is not boolean");
4606

4607
   return (op->result = vcode_add_reg(vtbool, VCODE_INVALID_STAMP));
3,411✔
4608
}
4609

4610
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
62,635✔
4611
{
4612
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
2,430,938✔
4613
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
210,866✔
4614
         bool match = true;
4615
         for (int i = 0; match && i < ndims; i++) {
29,691✔
4616
            match = other->args.items[i*3 + 1] == dims[i].left
14,888✔
4617
               && other->args.items[i*3 + 2] == dims[i].right
12,227✔
4618
               && other->args.items[i*3 + 3] == dims[i].dir;
26,745✔
4619
         }
4620
         if (match)
14,803✔
4621
            return other->result;
11,772✔
4622
      }
4623
   }
4624

4625
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
50,863✔
4626
   vcode_add_arg(op, data);
50,863✔
4627
   for (int i = 0; i < ndims; i++) {
102,632✔
4628
      vcode_add_arg(op, dims[i].left);
51,769✔
4629
      vcode_add_arg(op, dims[i].right);
51,769✔
4630
      vcode_add_arg(op, dims[i].dir);
51,769✔
4631
   }
4632

4633
   vcode_type_t ptr_type = vcode_reg_type(data);
50,863✔
4634
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
50,863✔
4635
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
50,863✔
4636
                "wrapped data is not pointer or signal");
4637

4638
#ifdef DEBUG
4639
   for (int i = 0; i < ndims; i++) {
102,632✔
4640
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
51,769✔
4641
                   "dimension %d left bound must be scalar", i + 1);
4642
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
51,769✔
4643
                   "dimension %d right bound must be scalar", i + 1);
4644
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
51,769✔
4645
                   "dimension %d direction must be bool", i + 1);
4646
   }
4647
#endif
4648

4649
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
101,726✔
4650
      ? vtype_pointed(ptr_type) : ptr_type;
50,863✔
4651

4652
   op->result = vcode_add_reg(vtype_uarray(ndims, elem), vcode_reg_stamp(data));
50,863✔
4653

4654
   return op->result;
50,863✔
4655
}
4656

4657
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
139,418✔
4658
                                  vcode_reg_t array, unsigned dim,
4659
                                  unsigned arg_index)
4660
{
4661
   // Reuse any previous operation in this block with the same arguments
4662
   VCODE_FOR_EACH_OP(other) {
1,656,160✔
4663
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,595,242✔
4664
          && (rtype == VCODE_INVALID_TYPE
32,866✔
4665
              || vtype_eq(rtype, vcode_reg_type(other->result))))
14,105✔
4666
         return other->result;
32,866✔
4667
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,562,376✔
4668
         return other->args.items[1 + (dim * 3) + arg_index];
45,634✔
4669
   }
4670

4671
   op_t *op = vcode_add_op(o);
60,918✔
4672
   vcode_add_arg(op, array);
60,918✔
4673
   op->dim = dim;
60,918✔
4674

4675
   vcode_type_t atype = vcode_reg_type(array);
60,918✔
4676
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
60,918✔
4677
                "cannot use %s with non-uarray type", vcode_op_string(o));
4678

4679
   vtype_t *vt = vcode_type_data(atype);
60,918✔
4680
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
60,918✔
4681

4682
   if (rtype == VCODE_INVALID_TYPE)
60,918✔
4683
      rtype = vtype_offset();
39,330✔
4684

4685
   return (op->result = vcode_add_reg(rtype, VCODE_INVALID_STAMP));
60,918✔
4686
}
4687

4688
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
51,371✔
4689
{
4690
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
51,371✔
4691
                         array, dim, 0);
4692
}
4693

4694
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
37,006✔
4695
{
4696
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
37,006✔
4697
                         array, dim, 1);
4698
}
4699

4700
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
51,041✔
4701
{
4702
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
51,041✔
4703
                         array, dim, 2);
4704
}
4705

4706
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
61,219✔
4707
{
4708
   VCODE_FOR_EACH_OP(other) {
1,031,429✔
4709
      if (other->kind == VCODE_OP_UARRAY_LEN) {
1,002,122✔
4710
         if (other->args.items[0] == array && other->dim == dim)
63,836✔
4711
            return other->result;
12,451✔
4712
      }
4713
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
938,286✔
4714
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
19,461✔
4715
                      "array dimension %d out of bounds", dim);
4716

4717
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
19,461✔
4718
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
19,461✔
4719
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
19,461✔
4720
         return emit_range_length(left_reg, right_reg, dir_reg);
19,461✔
4721
      }
4722
   }
4723

4724
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
29,307✔
4725
   vcode_add_arg(op, array);
29,307✔
4726
   op->dim = dim;
29,307✔
4727

4728
   vcode_type_t atype = vcode_reg_type(array);
29,307✔
4729
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
29,307✔
4730
                "cannot use uarray len with non-uarray type");
4731

4732
   vtype_t *vt = vcode_type_data(atype);
29,307✔
4733
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
29,307✔
4734

4735
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
29,307✔
4736

4737
   return op->result;
29,307✔
4738
}
4739

4740
vcode_reg_t emit_unwrap(vcode_reg_t array)
47,554✔
4741
{
4742
   VCODE_FOR_EACH_OP(other) {
2,432,436✔
4743
      if (other->kind == VCODE_OP_WRAP && other->result == array)
2,398,035✔
4744
         return other->args.items[0];
10,841✔
4745
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
2,387,194✔
4746
         return other->result;
2,312✔
4747
   }
4748

4749
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
34,401✔
4750
   vcode_add_arg(op, array);
34,401✔
4751

4752
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
34,401✔
4753
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
34,401✔
4754
                "unwrap can only only be used with uarray types");
4755

4756
   vcode_type_t elem = vt->elem;
34,401✔
4757

4758
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
34,401✔
4759
      ? elem : vtype_pointer(elem);
34,401✔
4760

4761
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
34,401✔
4762
}
4763

4764
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
49,412✔
4765
                            vcode_reg_t dir)
4766
{
4767
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
2,643,070✔
UNCOV
4768
      if (other->args.items[0] == left
×
UNCOV
4769
          && other->args.items[1] == right
×
UNCOV
4770
          && other->args.items[2] == dir)
×
UNCOV
4771
         return other->result;
×
4772
   }
4773

4774
   int64_t dir_const, l_low, l_high, r_low, r_high;
49,412✔
4775
   if (vcode_reg_const(dir, &dir_const)
49,412✔
4776
       && vcode_reg_bounds(left, &l_low, &l_high)
45,296✔
4777
       && vcode_reg_bounds(right, &r_low, &r_high)) {
45,296✔
4778

4779
      if (dir_const == RANGE_TO && l_low > r_high)
45,296✔
4780
         return emit_const(vtype_bool(), 1);
84✔
4781
      else if (dir_const == RANGE_TO && l_high <= r_low)
45,212✔
4782
         return emit_const(vtype_bool(), 0);
34,297✔
4783
      else if (dir_const == RANGE_DOWNTO && r_low > l_high)
10,915✔
4784
         return emit_const(vtype_bool(), 1);
1,022✔
4785
      else if (dir_const == RANGE_DOWNTO && r_high <= l_low)
9,893✔
4786
         return emit_const(vtype_bool(), 0);
2,645✔
4787
      else if (dir_const == RANGE_TO)
7,248✔
4788
         return emit_cmp(VCODE_CMP_GT, left, right);
3,863✔
4789
      else
4790
         return emit_cmp(VCODE_CMP_GT, right, left);
3,385✔
4791
   }
4792

4793
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
4,116✔
4794
   vcode_add_arg(op, left);
4,116✔
4795
   vcode_add_arg(op, right);
4,116✔
4796
   vcode_add_arg(op, dir);
4,116✔
4797

4798
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
4,116✔
4799
                "range left and right have different types");
4800
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
4,116✔
4801
                "dir argument to range length is not int");
4802

4803
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
4,116✔
4804
}
4805

4806
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
19,511✔
4807
                              vcode_reg_t dir)
4808
{
4809
   vcode_reg_t left_array = VCODE_INVALID_REG,
19,511✔
4810
      right_array = VCODE_INVALID_REG,
19,511✔
4811
      dir_array = VCODE_INVALID_REG;
19,511✔
4812
   int left_dim = -1, right_dim = -1, dir_dim = -1;
19,511✔
4813

4814
   VCODE_FOR_EACH_OP(other) {
393,348✔
4815
      if (other->kind == VCODE_OP_RANGE_LENGTH
380,842✔
4816
          && other->args.items[0] == left
9,626✔
4817
          && other->args.items[1] == right
7,438✔
4818
          && other->args.items[2] == dir)
7,005✔
4819
         return other->result;
7,005✔
4820
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
373,837✔
4821
         left_array = other->args.items[0];
501✔
4822
         left_dim = other->dim;
501✔
4823
      }
4824
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
373,336✔
4825
         right_array = other->args.items[0];
501✔
4826
         right_dim = other->dim;
501✔
4827
      }
4828
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
372,835✔
4829
         dir_array = other->args.items[0];
1,026✔
4830
         dir_dim = other->dim;
1,026✔
4831
      }
4832
   }
4833

4834
   if (left_array != VCODE_INVALID_REG && left_array == right_array
12,506✔
4835
       && right_array == dir_array && left_dim == right_dim
501✔
4836
       && right_dim == dir_dim)
501✔
4837
      return emit_uarray_len(left_array, left_dim);
501✔
4838

4839
   int64_t lconst, rconst, dconst;
12,005✔
4840
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
12,005✔
4841
       && vcode_reg_const(right, &rconst)) {
6,594✔
4842

4843
      int64_t diff;
2,726✔
4844
      if (dconst == RANGE_TO)
2,726✔
4845
         diff = rconst - lconst;
2,289✔
4846
      else
4847
         diff = lconst - rconst;
437✔
4848

4849
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
2,726✔
4850
   }
4851

4852
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
9,279✔
4853
   vcode_add_arg(op, left);
9,279✔
4854
   vcode_add_arg(op, right);
9,279✔
4855
   vcode_add_arg(op, dir);
9,279✔
4856

4857
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
9,279✔
4858
                "range left and right have different types");
4859
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
9,279✔
4860
                "dir argument to range length is not int");
4861

4862
   op->result = vcode_add_reg(vtype_offset(), vstamp_int(0, INT64_MAX));
9,279✔
4863

4864
   return op->result;
9,279✔
4865
}
4866

4867
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
78,653✔
4868
{
4869
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
716,453✔
4870
      if (other->hops == hops && other->address == var)
99,723✔
4871
         return other->result;
16,796✔
4872
   }
4873

4874
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
61,857✔
4875
   op->hops    = hops;
61,857✔
4876
   op->address = var;
61,857✔
4877

4878
   VCODE_ASSERT(hops > 0, "invalid hop count");
61,857✔
4879

4880
   vcode_unit_t vu = active_unit;
61,857✔
4881
   for (int i = 0; i < hops; i++) {
136,824✔
4882
      vu = vu->context;
74,967✔
4883
      VCODE_ASSERT(vu, "hop count is greater than depth");
74,967✔
4884
   }
4885

4886
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
61,857✔
4887

4888
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
61,857✔
4889

4890
   return op->result;
61,857✔
4891
}
4892

4893
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
27,558✔
4894
                             vcode_reg_t size, vcode_reg_t value,
4895
                             vcode_reg_t flags, vcode_reg_t locus,
4896
                             vcode_reg_t offset)
4897
{
4898
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
27,558✔
4899
   vcode_add_arg(op, count);
27,558✔
4900
   vcode_add_arg(op, size);
27,558✔
4901
   vcode_add_arg(op, value);
27,558✔
4902
   vcode_add_arg(op, flags);
27,558✔
4903
   vcode_add_arg(op, locus);
27,558✔
4904
   if (offset != VCODE_INVALID_REG)
27,558✔
4905
      vcode_add_arg(op, offset);
9,653✔
4906

4907
   vcode_type_t vtype = vcode_reg_type(value);
27,558✔
4908
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
27,558✔
4909
   VCODE_ASSERT(vtype_eq(vtype, type)
27,558✔
4910
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4911
                "init signal value type does not match signal type");
4912
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
27,558✔
4913
                "locus argument to init signal must be a debug locus");
4914
   VCODE_ASSERT(offset == VCODE_INVALID_REG
27,558✔
4915
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4916
                "init signal offset argument must have pointer type");
4917

4918
   vcode_type_t stype = vtype_signal(type);
27,558✔
4919
   return (op->result = vcode_add_reg(stype, VCODE_INVALID_STAMP));
27,558✔
4920
}
4921

4922
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
5,791✔
4923
{
4924
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
5,791✔
4925
   vcode_add_arg(op, signal);
5,791✔
4926
   vcode_add_arg(op, resolution);
5,791✔
4927

4928
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
5,791✔
4929
                "signal argument has wrong type");
4930

4931
   vcode_type_t rtype = vcode_reg_type(resolution);
5,791✔
4932
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
5,791✔
4933
                "resolution wrapper argument must be pointer");
4934
   VCODE_ASSERT(vtype_kind(vtype_pointed(rtype)) == VCODE_TYPE_RESOLUTION,
5,791✔
4935
                "resolution wrapper argument has wrong type");
4936
}
5,791✔
4937

4938
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
9,061✔
4939
{
4940
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
9,061✔
4941
   vcode_add_arg(op, src);
9,061✔
4942
   vcode_add_arg(op, dst);
9,061✔
4943
   vcode_add_arg(op, count);
9,061✔
4944

4945
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
9,061✔
4946
                "src argument to map signal is not a signal");
4947
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
9,061✔
4948
                "dst argument to map signal is not a signal");
4949
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
9,061✔
4950
                "count argument type to map signal is not offset");
4951
}
9,061✔
4952

4953
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
319✔
4954
{
4955
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
319✔
4956
   vcode_add_arg(op, src);
319✔
4957
   vcode_add_arg(op, dst);
319✔
4958
   vcode_add_arg(op, count);
319✔
4959

4960
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
319✔
4961
                "dst argument to map const is not a signal");
4962
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
319✔
4963
                "count argument type to map const is not offset");
4964
}
319✔
4965

4966
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
10,237✔
4967
{
4968
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
126,106✔
4969
      if (other->args.items[0] == target && other->args.items[1] == count)
16,945✔
4970
         return;
4971
   }
4972

4973
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
10,233✔
4974
   vcode_add_arg(op, target);
10,233✔
4975
   vcode_add_arg(op, count);
10,233✔
4976

4977
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
10,233✔
4978
                "target argument to drive signal is not a signal");
4979
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
10,233✔
4980
                "count argument type to drive signal is not offset");
4981
}
4982

4983
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
649✔
4984
                          vcode_reg_t count, vcode_reg_t reject,
4985
                          vcode_reg_t after)
4986
{
4987
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
649✔
4988
   vcode_add_arg(op, target);
649✔
4989
   vcode_add_arg(op, source);
649✔
4990
   vcode_add_arg(op, count);
649✔
4991
   vcode_add_arg(op, reject);
649✔
4992
   vcode_add_arg(op, after);
649✔
4993

4994
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
649✔
4995
                "target argument to transfer signal is not a signal");
4996
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
649✔
4997
                "count argument type to transfer signal is not offset");
4998
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
649✔
4999
                "source argument to transfer signal is not a signal");
5000
}
649✔
5001

5002
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
11,066✔
5003
                                    vcode_reg_t nlits)
5004
{
5005
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
170,069✔
5006
      if (other->args.items[0] == closure && other->args.items[1] == nlits)
22,949✔
UNCOV
5007
         return other->result;
×
5008
   }
5009

5010
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
11,066✔
5011
                "first argument to resolution wrapper must be closure");
5012

5013
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
11,066✔
5014
   vcode_add_arg(op, closure);
11,066✔
5015
   vcode_add_arg(op, nlits);
11,066✔
5016

5017
   return (op->result = vcode_add_reg(vtype_resolution(type),
11,066✔
5018
                                      VCODE_INVALID_STAMP));
5019
}
5020

5021
vcode_reg_t emit_closure(ident_t func, vcode_type_t rtype,
11,810✔
5022
                         const vcode_reg_t *args, int nargs)
5023
{
5024
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
177,674✔
5025
      if (other->func != func || other->args.count != nargs)
23,336✔
5026
         continue;
23,336✔
5027

5028
      bool match = true;
UNCOV
5029
      for (int i = 0; i < nargs; i++)
×
UNCOV
5030
         match &= other->args.items[i] == args[i];
×
5031

UNCOV
5032
      if (match)
×
UNCOV
5033
         return other->result;
×
5034
   }
5035

5036
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
11,810✔
5037
   op->func = func;
11,810✔
5038
   for (int i = 0; i < nargs; i++)
24,396✔
5039
      vcode_add_arg(op, args[i]);
12,586✔
5040

5041
   return (op->result = vcode_add_reg(vtype_closure(rtype),
11,810✔
5042
                                      VCODE_INVALID_STAMP));
5043
}
5044

5045
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
61,235✔
5046
{
5047
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
123,664✔
5048
      if (other->func == name)
51,424✔
5049
         return other->result;
24,154✔
5050
   }
5051

5052
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
37,081✔
5053
   op->func = name;
37,081✔
5054
   if (context != VCODE_INVALID_REG)
37,081✔
5055
      vcode_add_arg(op, context);
310✔
5056

5057
   VCODE_ASSERT(context == VCODE_INVALID_REG
37,081✔
5058
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5059
                "invalid protected init context argument");
5060
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
37,081✔
5061
                || active_unit->kind == VCODE_UNIT_PACKAGE
5062
                || active_unit->kind == VCODE_UNIT_THUNK,
5063
                "cannot use package init here");
5064
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
37,081✔
5065

5066
   return (op->result = vcode_add_reg(vtype_context(name),
37,081✔
5067
                                      VCODE_INVALID_STAMP));
5068
}
5069

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

5077
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
1,043✔
5078
      vcode_add_arg(op, path_name);
817✔
5079
      vcode_add_arg(op, inst_name);
817✔
5080

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

5087
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
1,043✔
5088
                "protected init type must be context");
5089
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
1,043✔
5090
                "invalid protected init context argument");
5091

5092
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
1,043✔
5093
}
5094

5095
void emit_process_init(vcode_reg_t closure, vcode_reg_t locus)
744✔
5096
{
5097
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
744✔
5098
   vcode_add_arg(op, closure);
744✔
5099
   vcode_add_arg(op, locus);
744✔
5100

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

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

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

5116
vcode_reg_t emit_context_upref(int hops)
30,467✔
5117
{
5118
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
223,535✔
5119
      if (other->hops == hops)
14,866✔
5120
         return other->result;
14,797✔
5121
   }
5122

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

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

5128
   vcode_unit_t vu = active_unit;
15,670✔
5129
   for (int i = 0; i < hops; i++) {
26,081✔
5130
      vu = vu->context;
10,411✔
5131
      VCODE_ASSERT(vu, "hop count is greater than depth");
10,411✔
5132
   }
5133

5134
   return (op->result = vcode_add_reg(vtype_context(vu->name),
15,670✔
5135
                                      VCODE_INVALID_STAMP));
5136
}
5137

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

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

5148
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
947✔
5149
}
5150

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

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

5161
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
56,381✔
5162
{
5163
   // Try scanning backwards through the block for another record ref
5164
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
4,335,242✔
5165
      if (other->args.items[0] == record && other->field == field)
800,851✔
5166
         return other->result;
6,047✔
5167
   }
5168

5169
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
50,334✔
5170
   op->field = field;
50,334✔
5171
   vcode_add_arg(op, record);
50,334✔
5172

5173
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
50,334✔
5174

5175
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
50,334✔
5176
                "argument to record ref must be a pointer");
5177

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

5182
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
50,334✔
5183

5184
   vcode_type_t field_type  = rtype->fields.items[field];
50,334✔
5185
   vcode_type_t result_type = field_type;
50,334✔
5186

5187
   const vtype_kind_t fkind = vtype_kind(field_type);
50,334✔
5188
   if (fkind == VCODE_TYPE_CARRAY)
50,334✔
5189
      result_type = vtype_elem(field_type);
7,105✔
5190
   else if (fkind == VCODE_TYPE_UARRAY)
5191
      result_type = field_type;
5192

5193
   op->result = vcode_add_reg(vtype_pointer(result_type), VCODE_INVALID_STAMP);
50,334✔
5194

5195
   return op->result;
50,334✔
5196
}
5197

5198
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
46,718✔
5199
{
5200
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
2,595,348✔
5201
      if (other->args.items[0] == array && other->args.items[1] == offset)
170,122✔
5202
         return other->result;
1,583✔
5203
   }
5204

5205
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
45,135✔
5206
   vcode_add_arg(op, array);
45,135✔
5207
   vcode_add_arg(op, offset);
45,135✔
5208

5209
   vcode_type_t rtype = vcode_reg_type(array);
45,135✔
5210
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
45,135✔
5211
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5212
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5213
                "argument to array ref must be a pointer or signal");
5214
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
45,135✔
5215
                "array ref offset argument must have offset type");
5216

5217
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
45,135✔
5218
}
5219

5220
vcode_reg_t emit_table_ref(vcode_reg_t array, vcode_reg_t stride,
874✔
5221
                           const vcode_reg_t *args, int nargs)
5222
{
5223
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_TABLE_REF) {
23,091✔
5224
      if (other->args.items[0] != array || other->args.items[1] != stride)
838✔
5225
         continue;
579✔
5226
      else if (other->args.count != nargs + 2)
259✔
UNCOV
5227
         continue;
×
5228

5229
      bool match = true;
5230
      for (int i = 0; i < nargs; i++)
636✔
5231
         match &= (other->args.items[i + 2] == args[i]);
377✔
5232

5233
      if (match)
259✔
5234
         return other->result;
33✔
5235
   }
5236

5237
   op_t *op = vcode_add_op(VCODE_OP_TABLE_REF);
841✔
5238
   vcode_add_arg(op, array);
841✔
5239
   vcode_add_arg(op, stride);
841✔
5240
   for (int i = 0; i < nargs; i++)
2,047✔
5241
      vcode_add_arg(op, args[i]);
1,206✔
5242

5243
   vcode_type_t rtype = vcode_reg_type(array);
841✔
5244
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER
841✔
5245
                && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY,
5246
                "argument to table ref must be a pointer or signal");
5247
   VCODE_ASSERT(vcode_reg_kind(stride) == VCODE_TYPE_OFFSET,
841✔
5248
                "table ref stride argument must have offset type");
5249

5250
   for (int i = 0; i < nargs; i++)
2,047✔
5251
      VCODE_ASSERT(vtype_is_integral(vcode_reg_type(args[i])),
1,206✔
5252
                   "table ref indices must be integral");
5253

5254
   return (op->result = vcode_add_reg(rtype, vcode_reg_stamp(array)));
841✔
5255
}
5256

5257
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
49,142✔
5258
{
5259
   int64_t cconst;
49,142✔
5260
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
49,142✔
5261
       && cconst == 0)
35,496✔
5262
      return;
7,405✔
5263
   else if (dest == src)
47,931✔
5264
      return;
5265

5266
   op_t *op = vcode_add_op(VCODE_OP_COPY);
41,737✔
5267
   vcode_add_arg(op, dest);
41,737✔
5268
   vcode_add_arg(op, src);
41,737✔
5269
   if (count != VCODE_INVALID_REG)
41,737✔
5270
      vcode_add_arg(op, count);
39,350✔
5271

5272
   vcode_type_t dtype = vcode_reg_type(dest);
41,737✔
5273
   vcode_type_t stype = vcode_reg_type(src);
41,737✔
5274

5275
   vtype_kind_t dkind = vtype_kind(dtype);
41,737✔
5276
   vtype_kind_t skind = vtype_kind(stype);
41,737✔
5277

5278
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
41,737✔
5279
                "destination type is not a pointer or access");
5280
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
41,737✔
5281
                "source type is not a pointer or access");
5282
   VCODE_ASSERT(vtype_eq(dtype, stype),
41,737✔
5283
                "source and destination types do not match");
5284
   VCODE_ASSERT(count == VCODE_INVALID_REG
41,737✔
5285
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5286
                "count is not offset type");
5287

5288
   op->type = vtype_pointed(dtype);
41,737✔
5289
}
5290

5291
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
5,963✔
5292
{
5293
   VCODE_FOR_EACH_OP(other) {
83,211✔
5294
      if (other->kind == VCODE_OP_CLEAR_EVENT)
77,320✔
5295
         break;
5296
      else if (other->kind == VCODE_OP_SCHED_EVENT
77,256✔
5297
               && other->args.items[0] == nets
3,602✔
5298
               && other->args.items[1] == n_elems)
12✔
5299
         return;
5300
   }
5301

5302
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
5,955✔
5303
   vcode_add_arg(op, nets);
5,955✔
5304
   vcode_add_arg(op, n_elems);
5,955✔
5305

5306
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
5,955✔
5307
                "nets argument to sched event must be signal");
5308
}
5309

5310
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
729✔
5311
{
5312
   VCODE_FOR_EACH_OP(other) {
3,347✔
5313
      if (other->kind == VCODE_OP_SCHED_EVENT)
2,618✔
5314
         break;
5315
      else if (other->kind == VCODE_OP_CLEAR_EVENT
2,618✔
5316
               && other->args.items[0] == nets
52✔
UNCOV
5317
               && other->args.items[1] == n_elems)
×
5318
         return;
5319
   }
5320

5321
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
729✔
5322
   vcode_add_arg(op, nets);
729✔
5323
   vcode_add_arg(op, n_elems);
729✔
5324

5325
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
729✔
5326
                "nets argument to clear event must be signal");
5327
}
5328

5329
void emit_sched_active(vcode_reg_t nets, vcode_reg_t n_elems)
533✔
5330
{
5331
   op_t *op = vcode_add_op(VCODE_OP_SCHED_ACTIVE);
533✔
5332
   vcode_add_arg(op, nets);
533✔
5333
   vcode_add_arg(op, n_elems);
533✔
5334

5335
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
533✔
5336
                "nets argument to sched active must be signal");
5337
}
533✔
5338

5339
void emit_sched_process(vcode_reg_t delay)
7,069✔
5340
{
5341
   op_t *op = vcode_add_op(VCODE_OP_SCHED_PROCESS);
7,069✔
5342
   vcode_add_arg(op, delay);
7,069✔
5343

5344
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
7,069✔
5345
                "delay must have integer type");
5346
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
7,069✔
5347
                || active_unit->kind == VCODE_UNIT_PROCESS,
5348
                "sched process only allowed in process or procedure");
5349
}
7,069✔
5350

5351
void emit_resume(ident_t func)
1,143✔
5352
{
5353
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
1,143✔
5354
   op->func = func;
1,143✔
5355

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

5360
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
7,332✔
5361
{
5362
   int64_t lconst;
7,332✔
5363
   if (vcode_reg_const(len, &lconst) && lconst == 0)
7,332✔
5364
      return;
41✔
5365

5366
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
7,291✔
5367
   vcode_add_arg(op, ptr);
7,291✔
5368
   vcode_add_arg(op, value);
7,291✔
5369
   vcode_add_arg(op, len);
7,291✔
5370

5371
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
7,291✔
5372
                "target of memset must have pointer type");
5373
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
7,291✔
5374
                "value of memset must have scalar type");
5375
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
7,291✔
5376
                "length of memset must have offset type");
5377
}
5378

5379
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
875✔
5380
               const vcode_block_t *blocks, int ncases)
5381
{
5382
   int64_t cval1, cval2;
875✔
5383
   bool is_const = vcode_reg_const(value, &cval1);
875✔
5384

5385
   for (int i = 0; i < ncases; i++) {
4,891✔
5386
      bool can_fold = false;
4,016✔
5387
      if (cases[i] == value)
4,016✔
5388
         can_fold = true;
5389
      else if (is_const && vcode_reg_const(cases[i], &cval2))
4,016✔
UNCOV
5390
         can_fold = (cval1 == cval2);
×
5391

UNCOV
5392
      if (can_fold) {
×
UNCOV
5393
         emit_jump(blocks[i]);
×
UNCOV
5394
         return;
×
5395
      }
5396
   }
5397

5398
   if (is_const) {
875✔
UNCOV
5399
      emit_jump(def);
×
5400
      return;
×
5401
   }
5402

5403
   op_t *op = vcode_add_op(VCODE_OP_CASE);
875✔
5404
   vcode_add_arg(op, value);
875✔
5405
   vcode_add_target(op, def);
875✔
5406

5407
   for (int i = 0; i < ncases; i++) {
4,891✔
5408
      vcode_add_arg(op, cases[i]);
4,016✔
5409
      vcode_add_target(op, blocks[i]);
4,016✔
5410

5411
#ifdef DEBUG
5412
      for (int j = 0; j < i; j++)
19,720✔
5413
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
15,704✔
5414
#endif
5415
   }
5416
}
5417

5418
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
2,073✔
5419
                    vcode_reg_t kind, vcode_reg_t status)
5420
{
5421
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
2,073✔
5422
   vcode_add_arg(op, file);
2,073✔
5423
   vcode_add_arg(op, name);
2,073✔
5424
   vcode_add_arg(op, length);
2,073✔
5425
   vcode_add_arg(op, kind);
2,073✔
5426
   if (status != VCODE_INVALID_REG)
2,073✔
5427
      vcode_add_arg(op, status);
33✔
5428

5429
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
2,073✔
5430
                "file open first argument must have file pointer type");
5431
}
2,073✔
5432

5433
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
363✔
5434
{
5435
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
363✔
5436
   vcode_add_arg(op, file);
363✔
5437
   vcode_add_arg(op, value);
363✔
5438
   if (length != VCODE_INVALID_REG)
363✔
5439
      vcode_add_arg(op, length);
287✔
5440

5441
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
363✔
5442
                "file write first argument must have file pointer type");
5443
}
363✔
5444

5445
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
120✔
5446
                    vcode_reg_t inlen, vcode_reg_t outlen)
5447
{
5448
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
120✔
5449
   vcode_add_arg(op, file);
120✔
5450
   vcode_add_arg(op, ptr);
120✔
5451
   if (inlen != VCODE_INVALID_REG) {
120✔
5452
      vcode_add_arg(op, inlen);
56✔
5453
      if (outlen != VCODE_INVALID_REG)
56✔
5454
         vcode_add_arg(op, outlen);
44✔
5455
   }
5456

5457
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
120✔
5458
                "file read first argument must have file pointer type");
5459
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
120✔
5460
                "file read pointer argument must have pointer type");
5461
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
120✔
5462
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5463
                "file read outlen argument must have pointer type");
5464
}
120✔
5465

5466
vcode_reg_t emit_null(vcode_type_t type)
19,533✔
5467
{
5468
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
399,238✔
5469
      if (vtype_eq(vcode_reg_type(other->result), type))
12,877✔
5470
         return other->result;
6,395✔
5471
   }
5472

5473
   op_t *op = vcode_add_op(VCODE_OP_NULL);
13,138✔
5474
   op->result = vcode_add_reg(type, VCODE_INVALID_STAMP);
13,138✔
5475

5476
   vtype_kind_t kind = vtype_kind(type);
13,138✔
5477
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
13,138✔
5478
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5479
                "null type must be file, access, context, or pointer");
5480

5481
   return op->result;
5482
}
5483

5484
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
881✔
5485
{
5486
   op_t *op = vcode_add_op(VCODE_OP_NEW);
881✔
5487
   if (length != VCODE_INVALID_REG)
881✔
5488
      vcode_add_arg(op, length);
763✔
5489

5490
   op->result = vcode_add_reg(vtype_access(type), VCODE_INVALID_STAMP);
881✔
5491

5492
   vtype_kind_t kind = vtype_kind(type);
881✔
5493
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
881✔
5494
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5495
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5496
                "new type must be int, real, record, access, or uarray");
5497
   VCODE_ASSERT(length == VCODE_INVALID_REG
881✔
5498
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5499
                "new length must have offset type");
5500

5501
   return op->result;
881✔
5502
}
5503

5504
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
4,042✔
5505
{
5506
   VCODE_FOR_EACH_OP(other) {
167,022✔
5507
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
164,020✔
5508
         return;
5509
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
163,421✔
5510
         return;
5511
   }
5512

5513
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
3,002✔
5514
   vcode_add_arg(op, ptr);
3,002✔
5515
   vcode_add_arg(op, locus);
3,002✔
5516

5517
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
3,002✔
5518
                "null check argument must be an access");
5519
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
3,002✔
5520
                "locus argument to null check must be a debug locus");
5521
}
5522

5523
void emit_deallocate(vcode_reg_t ptr)
469✔
5524
{
5525
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
469✔
5526
   vcode_add_arg(op, ptr);
469✔
5527

5528
   vcode_type_t ptype = vcode_reg_type(ptr);
469✔
5529
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
469✔
5530
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5531
                "deallocate argument must be pointer to access");
5532
}
469✔
5533

5534
vcode_reg_t emit_all(vcode_reg_t reg)
4,923✔
5535
{
5536
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
235,476✔
5537
      if (other->args.items[0] == reg)
14,261✔
5538
         return other->result;
1,040✔
5539
   }
5540

5541
   op_t *op = vcode_add_op(VCODE_OP_ALL);
3,883✔
5542
   vcode_add_arg(op, reg);
3,883✔
5543

5544
   vcode_type_t vtype = vcode_reg_type(reg);
3,883✔
5545

5546
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
3,883✔
5547
                "all argument must be an access");
5548

5549
   vcode_type_t pointed = vtype_pointed(vtype);
3,883✔
5550
   op->result = vcode_add_reg(vtype_pointer(pointed), vcode_reg_stamp(reg));
3,883✔
5551

5552
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
3,883✔
5553
                "cannot dereference opaque type");
5554

5555
   return op->result;
5556
}
5557

5558
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
18,065✔
5559
{
5560
   block_t *b = &(active_unit->blocks.items[active_block]);
18,065✔
5561
   for (int i = b->ops.count - 1; i >= 0; i--) {
431,562✔
5562
      const op_t *other = &(b->ops.items[i]);
414,244✔
5563
      if (other->kind == kind && other->args.items[0] == sig)
414,244✔
5564
         return other->result;
747✔
5565
   }
5566

5567
   op_t *op = vcode_add_op(kind);
17,318✔
5568
   vcode_add_arg(op, sig);
17,318✔
5569

5570
   vcode_type_t stype = vcode_reg_type(sig);
17,318✔
5571
   op->type = stype;
17,318✔
5572

5573
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
17,318✔
5574
                "argument r%d to resolved is not a signal", sig);
5575

5576
   vcode_type_t rtype = vtype_base(stype);
17,318✔
5577

5578
   const vtype_kind_t rkind = vtype_kind(rtype);
17,318✔
5579
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
17,318✔
UNCOV
5580
      rtype = vtype_elem(rtype);
×
5581

5582
   VCODE_ASSERT(vtype_is_scalar(rtype),
17,318✔
5583
                "resolved signal base type must be scalar");
5584

5585
   op->result = vcode_add_reg(vtype_pointer(rtype), vcode_reg_stamp(sig));
17,318✔
5586

5587
   return op->result;
17,318✔
5588
}
5589

5590
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
17,816✔
5591
{
5592
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
17,816✔
5593
}
5594

5595
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
249✔
5596
{
5597
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
249✔
5598
}
5599

5600
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
56✔
5601
{
5602
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
56✔
5603
   vcode_add_arg(op, signal);
56✔
5604
   if (len != VCODE_INVALID_REG)
56✔
5605
      vcode_add_arg(op, len);
12✔
5606

5607
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
56✔
5608
                "signal argument to last event must have signal type");
5609
   VCODE_ASSERT(len == VCODE_INVALID_REG
56✔
5610
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5611
                "length argument to last event must have offset type");
5612

5613
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
56✔
5614
}
5615

5616
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
60✔
5617
{
5618
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
60✔
5619
   vcode_add_arg(op, signal);
60✔
5620
   if (len != VCODE_INVALID_REG)
60✔
5621
      vcode_add_arg(op, len);
8✔
5622

5623
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
60✔
5624
                "signal argument to last active must have signal type");
5625
   VCODE_ASSERT(len == VCODE_INVALID_REG
60✔
5626
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5627
                "length argument to last active must have offset type");
5628

5629
   return (op->result = vcode_add_reg(vtype_time(), VCODE_INVALID_STAMP));
60✔
5630
}
5631

5632
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
7,131✔
5633
{
5634
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
7,131✔
5635
   vcode_add_arg(op, signal);
7,131✔
5636
   vcode_add_arg(op, locus);
7,131✔
5637

5638
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
7,131✔
5639
                "signal argument must have signal type");
5640
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
7,131✔
5641
                "locus argument must have debug locus type");
5642
}
7,131✔
5643

5644
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
48✔
5645
{
5646
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
48✔
5647
   vcode_add_arg(op, signal);
48✔
5648
   vcode_add_arg(op, len);
48✔
5649

5650
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
48✔
5651
                "signal argument to last active must have signal type");
5652
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
48✔
5653
                "length argument to last active must have offset type");
5654

5655
   return (op->result = vcode_add_reg(vtype_bool(), VCODE_INVALID_STAMP));
48✔
5656
}
5657

5658
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
436✔
5659
{
5660
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
436✔
5661
   vcode_add_arg(op, signal);
436✔
5662
   vcode_add_arg(op, len);
436✔
5663

5664
   vcode_type_t signal_type = vcode_reg_type(signal);
436✔
5665

5666
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
436✔
5667
                "signal argument to driving value must have signal type");
5668
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
436✔
5669
                "length argument to driving value must have offset type");
5670

5671
   vcode_type_t base_type = vtype_base(signal_type);
436✔
5672
   op->result = vcode_add_reg(vtype_pointer(base_type), VCODE_INVALID_STAMP);
436✔
5673

5674
   return op->result;
436✔
5675
}
5676

5677
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
54,908✔
5678
                       vcode_reg_t dim)
5679
{
5680
   if (rlen == llen)
54,908✔
5681
      return;
5682

5683
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
282,680✔
5684
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
3,916✔
5685
         return;
5686
   }
5687

5688
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
9,512✔
5689
   vcode_add_arg(op, llen);
9,512✔
5690
   vcode_add_arg(op, rlen);
9,512✔
5691
   vcode_add_arg(op, locus);
9,512✔
5692
   if (dim != VCODE_INVALID_REG)
9,512✔
5693
      vcode_add_arg(op, dim);
36✔
5694

5695
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
9,512✔
5696
                "locus argument to length check must be a debug locus");
5697
}
5698

5699
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
233✔
5700
{
5701
   int64_t cval;
233✔
5702
   if (vcode_reg_const(exp, &cval) && cval >= 0)
233✔
5703
      return;
73✔
5704

5705
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
2,119✔
5706
      if (other->args.items[0] == exp)
20✔
5707
         return;
5708
   }
5709

5710
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
160✔
5711
   vcode_add_arg(op, exp);
160✔
5712
   vcode_add_arg(op, locus);
160✔
5713

5714
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
160✔
5715
                "exp argument to exponent check must be a integer");
5716
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
160✔
5717
                "locus argument to exponent check must be a debug locus");
5718
}
5719

5720
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
3,465✔
5721
{
5722
   int64_t cval;
3,465✔
5723
   if (vcode_reg_const(denom, &cval) && cval != 0)
3,465✔
5724
      return;
3,350✔
5725

5726
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
3,054✔
5727
      if (other->args.items[0] == denom)
64✔
5728
         return;
5729
   }
5730

5731
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
115✔
5732
   vcode_add_arg(op, denom);
115✔
5733
   vcode_add_arg(op, locus);
115✔
5734

5735
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
115✔
5736
                "denom argument to zero check must be a integer");
5737
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
115✔
5738
                "locus argument to zero check must be a debug locus");
5739
}
5740

5741
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
133,296✔
5742
                                   vcode_reg_t right, vcode_reg_t dir)
5743
{
5744
   int64_t dconst;
133,296✔
5745
   if (!vcode_reg_const(dir, &dconst))
133,296✔
5746
      return false;
5747

5748
   int64_t lconst, rconst;
120,099✔
5749
   if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
120,099✔
5750
      const bool is_null = (dconst == RANGE_TO && lconst > rconst)
87,206✔
5751
         || (dconst == RANGE_DOWNTO && rconst > lconst);
178,689✔
5752

5753
      int64_t low, high;
91,484✔
5754
      if (vcode_reg_bounds(reg, &low, &high)) {
91,484✔
5755
         const bool ok_static =
182,968✔
5756
            (dconst == RANGE_TO && low >= lconst && high <= rconst)
87,206✔
5757
            || (dconst == RANGE_DOWNTO && low >= rconst && high <= lconst)
11,744✔
5758
            || (!is_null && (reg == left || reg == right));
99,384✔
5759

5760
         return ok_static;
91,484✔
5761
      }
5762
   }
5763
   else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
28,615✔
5764
      vstamp_t *lbounds = vcode_stamp_data(vcode_reg_data(left)->stamp);
25,797✔
5765
      vstamp_t *rbounds = vcode_stamp_data(vcode_reg_data(right)->stamp);
25,797✔
5766

5767
      assert(lbounds->kind == VCODE_STAMP_REAL);
25,797✔
5768
      assert(rbounds->kind == VCODE_STAMP_REAL);
25,797✔
5769

5770
      double low, high;
25,797✔
5771

5772
      reg_t *rr = vcode_reg_data(reg);
25,797✔
5773
      vstamp_t *bounds = vcode_stamp_data(rr->stamp);
25,797✔
5774
      if (bounds != NULL) {
25,797✔
5775
         assert(bounds->kind == VCODE_STAMP_REAL);
16,983✔
5776
         low = bounds->u.real.low;
16,983✔
5777
         high = bounds->u.real.high;
16,983✔
5778
      }
5779
      else {
5780
         vtype_t *type = vcode_type_data(rr->type);
8,814✔
5781
         assert(type->kind == VCODE_TYPE_REAL);
8,814✔
5782
         low = type->rlow;
8,814✔
5783
         high = type->rhigh;
8,814✔
5784
      }
5785

5786
      if (isfinite(low) && lbounds->u.real.low == -DBL_MAX
25,797✔
5787
          && isfinite(high) && rbounds->u.real.high == DBL_MAX) {
24,847✔
5788
         // Covers the complete double range so can never overflow
5789
         return true;
24,847✔
5790
      }
5791
   }
5792

5793
   return false;
5794
}
5795

5796
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
134,501✔
5797
                              vcode_reg_t left, vcode_reg_t right,
5798
                              vcode_reg_t dir, vcode_reg_t locus,
5799
                              vcode_reg_t hint)
5800
{
5801
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
6,506,204✔
5802
      if (other->args.items[0] == reg && other->args.items[1] == left
25,942✔
5803
          && other->args.items[2] == right && other->args.items[3] == dir)
1,436✔
5804
         return;
5805
   }
5806

5807
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
133,296✔
5808
      emit_comment("Elided bounds check for r%d", reg);
108,431✔
5809
      return;
108,431✔
5810
   }
5811

5812
   op_t *op = vcode_add_op(kind);
24,865✔
5813
   vcode_add_arg(op, reg);
24,865✔
5814
   vcode_add_arg(op, left);
24,865✔
5815
   vcode_add_arg(op, right);
24,865✔
5816
   vcode_add_arg(op, dir);
24,865✔
5817
   vcode_add_arg(op, locus);
24,865✔
5818
   vcode_add_arg(op, hint);
24,865✔
5819

5820
   VCODE_ASSERT(vtype_is_numeric(vcode_reg_type(reg)),
24,865✔
5821
                "argument to bounds check must be numeric");
5822
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
24,865✔
5823
                "locus argument to bounds check must be a debug locus");
5824
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
24,865✔
5825
                "hint argument to bounds check must be a debug locus");
5826
}
5827

5828
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
30,314✔
5829
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5830
{
5831
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
30,314✔
5832
}
30,314✔
5833

5834
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
104,187✔
5835
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5836
{
5837
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
104,187✔
5838
}
104,187✔
5839

5840
void emit_dir_check(vcode_reg_t reg, vcode_reg_t dir, vcode_reg_t locus)
4,453✔
5841
{
5842
   if (reg == dir)
4,453✔
5843
      return;
5844

5845
   op_t *op = vcode_add_op(VCODE_OP_DIR_CHECK);
3,227✔
5846
   vcode_add_arg(op, reg);
3,227✔
5847
   vcode_add_arg(op, dir);
3,227✔
5848
   vcode_add_arg(op, locus);
3,227✔
5849

5850
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
3,227✔
5851
                "locus argument to dir check must be a debug locus");
5852
}
5853

5854
void emit_package_scope(vcode_reg_t locus)
72✔
5855
{
5856
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
72✔
5857
   vcode_add_arg(op, locus);
72✔
5858

5859
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
72✔
5860
                "locus argument to package scope must be a debug locus");
5861
}
72✔
5862

5863
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
1,103✔
5864
{
5865
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
1,103✔
5866
   vcode_add_arg(op, locus);
1,103✔
5867
   op->type = type;
1,103✔
5868

5869
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,103✔
5870
                "locus argument to array scope must be a debug locus");
5871
}
1,103✔
5872

5873
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
2,866✔
5874
{
5875
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
2,866✔
5876
   vcode_add_arg(op, locus);
2,866✔
5877
   op->type = type;
2,866✔
5878

5879
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,866✔
5880
                "locus argument to record scope must be a debug locus");
5881
}
2,866✔
5882

5883
void emit_pop_scope(void)
4,041✔
5884
{
5885
   vcode_add_op(VCODE_OP_POP_SCOPE);
4,041✔
5886
}
4,041✔
5887

5888
vcode_reg_t emit_debug_locus(object_t *obj)
260,874✔
5889
{
5890
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
10,943,423✔
5891
      if (other->object == obj)
1,372,757✔
5892
         return other->result;
26,870✔
5893
   }
5894

5895
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
234,004✔
5896
   op->object = obj;
234,004✔
5897
   op->result = vcode_add_reg(vtype_debug_locus(), VCODE_INVALID_STAMP);
234,004✔
5898

5899
   return op->result;
234,004✔
5900
}
5901

UNCOV
5902
void emit_debug_out(vcode_reg_t reg)
×
5903
{
UNCOV
5904
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
UNCOV
5905
   vcode_add_arg(op, reg);
×
UNCOV
5906
}
×
5907

5908
void emit_cover_stmt(vcode_reg_t counters, uint32_t tag)
1,571✔
5909
{
5910
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,571✔
5911
   vcode_add_arg(op, counters);
1,571✔
5912
   op->tag = tag;
1,571✔
5913

5914
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
1,571✔
5915
                "counters argument must be pointer");
5916
}
1,571✔
5917

5918
void emit_cover_branch(vcode_reg_t counters, uint32_t tag)
683✔
5919
{
5920
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
683✔
5921
   vcode_add_arg(op, counters);
683✔
5922
   op->tag = tag;
683✔
5923

5924
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
683✔
5925
                "counters argument must be pointer");
5926
}
683✔
5927

5928
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
462✔
5929
{
5930
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
462✔
5931
   vcode_add_arg(op, signal);
462✔
5932
   op->tag = tag;
462✔
5933
}
462✔
5934

5935
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
18✔
5936
{
5937
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
18✔
5938
   vcode_add_arg(op, signal);
18✔
5939
   vcode_add_arg(op, low);
18✔
5940
   op->tag = tag;
18✔
5941
}
18✔
5942

5943
void emit_cover_expr(vcode_reg_t counters, uint32_t tag)
1,144✔
5944
{
5945
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
1,144✔
5946
   vcode_add_arg(op, counters);
1,144✔
5947
   op->tag = tag;
1,144✔
5948

5949
   VCODE_ASSERT(vcode_reg_kind(counters) == VCODE_TYPE_POINTER,
1,144✔
5950
                "counters argument must be pointer");
5951
}
1,144✔
5952

5953
void emit_unreachable(vcode_reg_t locus)
1,945✔
5954
{
5955
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
1,945✔
5956
   if (locus != VCODE_INVALID_REG)
1,945✔
5957
      vcode_add_arg(op, locus);
167✔
5958
}
1,945✔
5959

5960
vcode_reg_t emit_undefined(vcode_type_t type, vcode_stamp_t stamp)
34✔
5961
{
5962
   active_unit->flags |= UNIT_UNDEFINED;
34✔
5963

5964
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
34✔
5965
   op->result = vcode_add_reg(type, stamp);
34✔
5966

5967
   return op->result;
34✔
5968
}
5969

5970
void emit_debug_info(const loc_t *loc)
4,080,813✔
5971
{
5972
   if (!loc_invalid_p(loc))
4,080,813✔
5973
      vcode_block_data()->last_loc = *loc;
4,050,113✔
5974
}
4,080,813✔
5975

5976
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
13,365✔
5977
{
5978
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
488,179✔
5979
      if (other->args.items[0] == context && other->ident == name)
18,977✔
5980
         return other->result;
6,337✔
5981
   }
5982

5983
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
7,028✔
5984
   vcode_add_arg(op, context);
7,028✔
5985
   op->ident = name;
7,028✔
5986

5987
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
7,028✔
5988
                "first argument to link var must be context");
5989

5990
   vcode_stamp_t stamp = VCODE_INVALID_STAMP;
7,028✔
5991

5992
   if (vtype_kind(type) == VCODE_TYPE_CARRAY)
7,028✔
5993
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)), stamp);
790✔
5994
   else
5995
      op->result = vcode_add_reg(vtype_pointer(type), stamp);
6,238✔
5996

5997
   return op->result;
7,028✔
5998
}
5999

6000
vcode_reg_t emit_link_package(ident_t name)
17,545✔
6001
{
6002
   VCODE_FOR_EACH_OP(other) {
650,672✔
6003
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
641,812✔
6004
         return other->result;
7,760✔
6005
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
634,052✔
6006
         return other->result;
925✔
6007
   }
6008

6009
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
8,860✔
6010
   op->ident = name;
8,860✔
6011

6012
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
8,860✔
6013

6014
   vcode_type_t type = vtype_context(name);
8,860✔
6015
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
8,860✔
6016
}
6017

6018
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
1,136✔
6019
{
6020
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
2,740✔
UNCOV
6021
      if (other->args.items[0] == state)
×
6022
         return;
6023
   }
6024

6025
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
1,136✔
6026
   vcode_add_arg(op, state);
1,136✔
6027
   if (strong != VCODE_INVALID_REG)
1,136✔
6028
      vcode_add_arg(op, strong);
48✔
6029

6030
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
1,136✔
6031
                "state must have integer type");
6032
   VCODE_ASSERT(strong == VCODE_INVALID_REG
1,136✔
6033
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
6034
                "strong argument not is not boolean");
6035
}
6036

6037
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
68✔
6038
                               vcode_reg_t locus, vcode_reg_t bounds)
6039
{
6040
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
68✔
6041
   vcode_add_arg(op, value);
68✔
6042
   vcode_add_arg(op, context);
68✔
6043
   vcode_add_arg(op, locus);
68✔
6044
   if (bounds != VCODE_INVALID_REG)
68✔
6045
      vcode_add_arg(op, bounds);
8✔
6046

6047
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
68✔
6048
                "invalid reflect value context argument");
6049
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
68✔
6050
                "locus argument to reflect value must be a debug locus");
6051

6052
   vcode_type_t type = vtype_access(vtype_opaque());
68✔
6053
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
68✔
6054
}
6055

6056
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
68✔
6057
                                 vcode_reg_t bounds)
6058
{
6059
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
68✔
6060
   vcode_add_arg(op, context);
68✔
6061
   vcode_add_arg(op, locus);
68✔
6062
   if (bounds != VCODE_INVALID_REG)
68✔
6063
      vcode_add_arg(op, bounds);
12✔
6064

6065
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
68✔
6066
                "invalid reflect value context argument");
6067
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
68✔
6068
                "locus argument to reflect value must be a debug locus");
6069

6070
   vcode_type_t type = vtype_access(vtype_opaque());
68✔
6071
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
68✔
6072
}
6073

6074
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
352✔
6075
                                  int nargs)
6076
{
6077
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
352✔
6078
   op->func = func;
352✔
6079

6080
   for (int i = 0; i < nargs; i++)
816✔
6081
      vcode_add_arg(op, args[i]);
464✔
6082

6083
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
352✔
6084
}
6085

6086
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
45✔
6087
{
6088
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
45✔
6089
   vcode_add_arg(op, left);
45✔
6090
   vcode_add_arg(op, right);
45✔
6091

6092
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
45✔
6093
                "or trigger left argument must be trigger");
6094
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
45✔
6095
                "or trigger right argument must be trigger");
6096

6097
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
45✔
6098
}
6099

6100
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
86✔
6101
{
6102
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
86✔
6103
   vcode_add_arg(op, left);
86✔
6104
   vcode_add_arg(op, right);
86✔
6105

6106
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
86✔
6107
                "cmp trigger left argument must be signal");
6108
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
86✔
6109
                "cmp trigger right argument must be integer");
6110

6111
   return (op->result = vcode_add_reg(vtype_trigger(), VCODE_INVALID_STAMP));
86✔
6112
}
6113

6114
void emit_add_trigger(vcode_reg_t trigger)
493✔
6115
{
6116
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
493✔
6117
   vcode_add_arg(op, trigger);
493✔
6118

6119
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
493✔
6120
                "add trigger argument must be trigger");
6121
}
493✔
6122

6123
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
239✔
6124
                               vcode_type_t type, vcode_stamp_t stamp,
6125
                               const vcode_reg_t *args, int nargs)
6126
{
6127
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
239✔
6128
   op->type  = type;
239✔
6129
   op->ident = scope;
239✔
6130
   vcode_add_arg(op, locus);
239✔
6131
   for (int i = 0; i < nargs; i++)
279✔
6132
      vcode_add_arg(op, args[i]);
40✔
6133

6134
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
239✔
6135
                "bind external argument must be locus");
6136

6137
   op->result = vcode_add_reg(vtype_pointer(type), VCODE_INVALID_STAMP);
239✔
6138
   vcode_reg_data(op->result)->stamp = stamp;
239✔
6139
   return op->result;
239✔
6140
}
6141

6142
void emit_put_driver(vcode_reg_t target, vcode_reg_t count, vcode_reg_t values)
667✔
6143
{
6144
   op_t *op = vcode_add_op(VCODE_OP_PUT_DRIVER);
667✔
6145
   vcode_add_arg(op, target);
667✔
6146
   vcode_add_arg(op, count);
667✔
6147
   vcode_add_arg(op, values);
667✔
6148

6149
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
667✔
6150
                "put driver target is not signal");
6151
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
667✔
6152
                "put driver count is not offset type");
6153
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
667✔
6154
                "signal cannot be values argument for put driver");
6155
}
667✔
6156

6157
void emit_deposit_signal(vcode_reg_t target, vcode_reg_t count,
33✔
6158
                         vcode_reg_t values)
6159
{
6160
   op_t *op = vcode_add_op(VCODE_OP_DEPOSIT_SIGNAL);
33✔
6161
   vcode_add_arg(op, target);
33✔
6162
   vcode_add_arg(op, count);
33✔
6163
   vcode_add_arg(op, values);
33✔
6164

6165
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
33✔
6166
                "deposit signal target is not signal");
6167
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
33✔
6168
                "deposit signal count is not offset type");
6169
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
33✔
6170
                "signal cannot be values argument for deposit signal");
6171
}
33✔
6172

6173
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
1,466✔
6174
{
6175
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
1,466✔
6176
   vcode_add_arg(op, spec);
1,466✔
6177
   vcode_add_arg(op, length);
1,466✔
6178
   if (locus != VCODE_INVALID_REG)
1,466✔
6179
      vcode_add_arg(op, locus);
1,248✔
6180

6181
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
1,466✔
6182
                "spec argument to bind foreign must be a pointer");
6183
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
1,466✔
6184
                "length argument to bind foreign must be offset");
6185
   VCODE_ASSERT(locus == VCODE_INVALID_REG
1,466✔
6186
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6187
                "locus argument to bind foreign value must be a debug locus");
6188
}
1,466✔
6189

6190
vcode_reg_t emit_instance_name(vcode_reg_t kind)
7,190✔
6191
{
6192
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
7,190✔
6193
   vcode_add_arg(op, kind);
7,190✔
6194

6195
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
7,190✔
6196
                "kind argument to instance name must be offset");
6197

6198
   vcode_type_t type = vtype_uarray(1, vtype_char());
7,190✔
6199
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
7,190✔
6200
}
6201

6202
vcode_reg_t emit_get_counters(ident_t block)
958✔
6203
{
6204
   op_t *op = vcode_add_op(VCODE_OP_GET_COUNTERS);
958✔
6205
   op->ident = block;
958✔
6206

6207
   vcode_type_t vint32 = vtype_int(INT32_MIN, INT32_MAX);
958✔
6208
   vcode_type_t type = vtype_pointer(vint32);
958✔
6209
   return (op->result = vcode_add_reg(type, VCODE_INVALID_STAMP));
958✔
6210
}
6211

6212
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
14,324✔
6213
{
6214
   vcode_state_t state;
14,324✔
6215
   vcode_state_save(&state);
14,324✔
6216

6217
   vcode_select_unit(vu);
14,324✔
6218

6219
   const int nblocks = vcode_count_blocks();
14,324✔
6220
   for (int i = 0; i < nblocks; i++) {
36,093✔
6221
      vcode_select_block(i);
21,769✔
6222

6223
      const int nops = vcode_count_ops();
21,769✔
6224
      for (int op = 0; op < nops; op++) {
427,554✔
6225
         switch (vcode_get_op(op)) {
405,785✔
6226
         case VCODE_OP_LINK_PACKAGE:
500✔
6227
            (*fn)(vcode_get_ident(op), ctx);
500✔
6228
            break;
500✔
6229
         case VCODE_OP_FCALL:
15,769✔
6230
         case VCODE_OP_PCALL:
6231
         case VCODE_OP_CLOSURE:
6232
         case VCODE_OP_PROTECTED_INIT:
6233
         case VCODE_OP_PACKAGE_INIT:
6234
         case VCODE_OP_FUNCTION_TRIGGER:
6235
            (*fn)(vcode_get_func(op), ctx);
15,769✔
6236
            break;
15,769✔
6237
         default:
6238
            break;
6239
         }
6240
      }
6241
   }
6242

6243
   vcode_state_restore(&state);
14,324✔
6244
}
14,324✔
6245

6246
#if VCODE_CHECK_UNIONS
6247
#define OP_USE_COUNT_U0(x)                                              \
6248
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6249
#define OP_USE_COUNT_U1(x)                                              \
6250
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6251
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6252
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6253

6254
__attribute__((constructor))
6255
static void vcode_check_unions(void)
6256
{
6257
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6258
   for (int i = 0; i < 256; i++) {
6259
      assert(OP_USE_COUNT_U0(i) <= 1);
6260
      assert(OP_USE_COUNT_U1(i) <= 1);
6261
   }
6262
}
6263
#endif  // VCODE_CHECK_UNIONS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc