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

nickg / nvc / 6604118477

22 Oct 2023 01:25PM UTC coverage: 91.218% (+0.3%) from 90.889%
6604118477

push

github

nickg
Generate unique name mangling for predefined functions

19 of 19 new or added lines in 5 files covered. (100.0%)

49523 of 54291 relevant lines covered (91.22%)

584870.41 hits per line

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

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

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

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

35
DECLARE_AND_DEFINE_ARRAY(vcode_reg);
5,075,371✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
211,164✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
38,564✔
38

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

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

109
DECLARE_AND_DEFINE_ARRAY(op);
1,433,300✔
110

111
typedef struct {
112
   op_array_t ops;
113
   loc_t      last_loc;
114
} block_t;
115

116
typedef struct {
117
   vcode_type_t type;
118
   vcode_type_t bounds;
119
} reg_t;
120

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

148
typedef struct {
149
   vcode_type_t      type;
150
   vcode_type_t      bounds;
151
   ident_t           name;
152
   vcode_var_flags_t flags;
153
} var_t;
154

155
typedef struct {
156
   vcode_type_t type;
157
   vcode_type_t bounds;
158
   ident_t      name;
159
   vcode_reg_t  reg;
160
} param_t;
161

162
DECLARE_AND_DEFINE_ARRAY(param);
27,216✔
163
DECLARE_AND_DEFINE_ARRAY(var);
37,695✔
164
DECLARE_AND_DEFINE_ARRAY(reg);
1,158,750✔
165
DECLARE_AND_DEFINE_ARRAY(block);
117,328✔
166
DECLARE_AND_DEFINE_ARRAY(vtype);
2,210,130✔
167

168
typedef enum {
169
   UNIT_UNDEFINED     = (1 << 1),
170
   UNIT_ESCAPING_TLAB = (1 << 2)
171
} unit_flags_t;
172

173
struct _vcode_unit {
174
   vunit_kind_t   kind;
175
   vcode_unit_t   context;
176
   ident_t        name;
177
   vcode_type_t   result;
178
   block_array_t  blocks;
179
   reg_array_t    regs;
180
   vtype_array_t  types;
181
   var_array_t    vars;
182
   param_array_t  params;
183
   unsigned       depth;
184
   unit_flags_t   flags;
185
   vcode_unit_t   children;
186
   vcode_unit_t   next;
187
   ident_t        module;
188
   ptrdiff_t      offset;
189
};
190

191
#define MASK_CONTEXT(x)   ((x) >> 24)
192
#define MASK_INDEX(x)     ((x) & 0xffffff)
193
#define MAKE_HANDLE(c, i) (((c) & 0xff) << 24 | ((i) & 0xffffff))
194

195
#define VCODE_ASSERT(expr, ...) do                                      \
196
      if (unlikely(!(expr))) {                                          \
197
         vcode_dump_with_mark(vcode_block_data()->ops.count - 1,        \
198
                              NULL, NULL);                              \
199
         fatal_trace(__VA_ARGS__);                                      \
200
      } while (0)
201

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

209
#define VCODE_FOR_EACH_MATCHING_OP(name, k) \
210
   VCODE_FOR_EACH_OP(name) if (name->kind == k)
211

212
#define VCODE_VERSION      31
213
#define VCODE_CHECK_UNIONS 0
214

215
static __thread vcode_unit_t     active_unit   = NULL;
216
static __thread vcode_block_t    active_block  = VCODE_INVALID_BLOCK;
217
static __thread vcode_dump_fn_t  dump_callback = NULL;
218
static __thread void            *dump_arg      = NULL;
219

220
static inline int64_t sadd64(int64_t a, int64_t b)
25,688✔
221
{
222
   int64_t result;
25,688✔
223
   if (__builtin_add_overflow(a, b, &result))
25,688✔
224
      return b < 0 ? INT64_MIN : INT64_MAX;
9,178✔
225

226
   return result;
227
}
228

229
static inline int64_t ssub64(int64_t a, int64_t b)
35,696✔
230
{
231
   int64_t result;
35,696✔
232
   if (__builtin_sub_overflow(a, b, &result))
35,696✔
233
      return b > 0 ? INT64_MIN : INT64_MAX;
4,026✔
234

235
   return result;
236
}
237

238
static inline int64_t smul64(int64_t a, int64_t b)
7,568✔
239
{
240
   int64_t result;
7,568✔
241
   if (__builtin_mul_overflow(a, b, &result))
7,568✔
242
      return (a > 0 && b > 0) || (a < 0 && b < 0) ? INT64_MAX : INT64_MIN;
3,573✔
243

244
   return result;
245
}
246

247
static vcode_reg_t vcode_add_reg(vcode_type_t type)
1,158,750✔
248
{
249
   assert(active_unit != NULL);
1,158,750✔
250

251
   vcode_reg_t reg = active_unit->regs.count;
1,158,750✔
252
   reg_t *r = reg_array_alloc(&(active_unit->regs));
1,158,750✔
253
   memset(r, '\0', sizeof(reg_t));
1,158,750✔
254
   r->type   = type;
1,158,750✔
255
   r->bounds = type;
1,158,750✔
256

257
   return reg;
1,158,750✔
258
}
259

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

267
static op_t *vcode_add_op(vcode_op_t kind)
1,433,300✔
268
{
269
   assert(active_unit != NULL);
1,433,300✔
270
   assert(active_block != VCODE_INVALID_BLOCK);
1,433,300✔
271

272
   VCODE_ASSERT(
1,433,300✔
273
      !vcode_block_finished(),
274
      "attempt to add to already finished block %d", active_block);
275

276
   block_t *block = vcode_block_data();
1,433,300✔
277

278
   op_t *op = op_array_alloc(&(block->ops));
1,433,300✔
279
   memset(op, '\0', sizeof(op_t));
1,433,300✔
280
   op->kind   = kind;
1,433,300✔
281
   op->result = VCODE_INVALID_REG;
1,433,300✔
282
   op->loc    = block->last_loc;
1,433,300✔
283

284
   return op;
1,433,300✔
285
}
286

287
static void vcode_add_arg(op_t *op, vcode_reg_t arg)
2,450,790✔
288
{
289
   vcode_reg_array_add(&(op->args), arg);
2,450,790✔
290
}
2,450,790✔
291

292
static void vcode_add_target(op_t *op, vcode_block_t block)
103,611✔
293
{
294
   vcode_block_array_add(&(op->targets), block);
103,611✔
295
}
103,611✔
296

297
static op_t *vcode_op_data(int op)
10,014,200✔
298
{
299
   assert(active_unit != NULL);
10,014,200✔
300
   assert(active_block != VCODE_INVALID_BLOCK);
10,014,200✔
301

302
   block_t *b = &(active_unit->blocks.items[active_block]);
10,014,200✔
303
   return op_array_nth_ptr(&(b->ops), op);
10,014,200✔
304
}
305

306
static op_t *vcode_find_definition(vcode_reg_t reg)
1,203,680✔
307
{
308
   for (int i = active_block; i >= 0; i--) {
1,251,320✔
309
      block_t *b = &(active_unit->blocks.items[i]);
1,248,360✔
310
      for (int j = b->ops.count - 1; j >= 0; j--) {
22,878,600✔
311
         if (b->ops.items[j].result == reg)
22,831,000✔
312
            return &(b->ops.items[j]);
1,200,730✔
313
      }
314
   }
315

316
   return NULL;
317
}
318

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

336
static reg_t *vcode_reg_data(vcode_reg_t reg)
6,138,150✔
337
{
338
   assert(active_unit != NULL);
6,138,150✔
339
   assert(reg != VCODE_INVALID_REG);
6,138,150✔
340
   return reg_array_nth_ptr(&(active_unit->regs), reg);
6,138,150✔
341
}
342

343
static vtype_t *vcode_type_data(vcode_type_t type)
62,298,500✔
344
{
345
   assert(type != VCODE_INVALID_TYPE);
62,298,500✔
346
   assert(active_unit != NULL);
62,298,500✔
347
   vcode_unit_t unit = active_unit;
62,298,500✔
348

349
   int depth = MASK_CONTEXT(type);
62,298,500✔
350
   assert(depth <= unit->depth);
62,298,500✔
351
   while (depth != unit->depth)
63,212,900✔
352
      unit = unit->context;
914,328✔
353

354
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
62,298,500✔
355
}
356

357
static var_t *vcode_var_data(vcode_var_t var)
294,809✔
358
{
359
   assert(active_unit != NULL);
294,809✔
360
   assert(var != VCODE_INVALID_VAR);
294,809✔
361

362
   return var_array_nth_ptr(&(active_unit->vars), var);
294,809✔
363
}
364

365
void vcode_heap_allocate(vcode_reg_t reg)
32,774✔
366
{
367
   op_t *defn = vcode_find_definition(reg);
32,774✔
368
   if (defn == NULL) {
32,774✔
369
      // It is always safe to return a pointer to an argument
370
      return;
371
   }
372

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

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

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

398
   case VCODE_OP_VAR_UPREF:
710✔
399
      {
400
         vcode_state_t state;
710✔
401
         vcode_state_save(&state);
710✔
402

403
         for (int i = 0; i < defn->hops; i++)
1,420✔
404
            vcode_select_unit(vcode_unit_context());
710✔
405

406
         vcode_var_data(defn->address)->flags |= VAR_HEAP;
710✔
407
         active_unit->flags |= UNIT_ESCAPING_TLAB;
710✔
408

409
         vcode_state_restore(&state);
710✔
410
      }
411
      break;
710✔
412

413
   case VCODE_OP_ARRAY_REF:
175✔
414
      vcode_heap_allocate(defn->args.items[0]);
175✔
415
      break;
175✔
416

417
   case VCODE_OP_WRAP:
8,607✔
418
   case VCODE_OP_UNWRAP:
419
   case VCODE_OP_RESOLVED:
420
      vcode_heap_allocate(defn->args.items[0]);
8,607✔
421
      break;
8,607✔
422

423
   case VCODE_OP_LAST_VALUE:
424
      // Returns a pointer into the C heap
425
      break;
426

427
   case VCODE_OP_LOAD:
2,259✔
428
      {
429
         if (vcode_reg_kind(reg) != VCODE_TYPE_UARRAY)
2,259✔
430
            return;
431

432
         // Any store to this variable must be heap allocated
433
         for (int i = 0; i < active_unit->blocks.count; i++) {
21,361✔
434
            block_t *b = &(active_unit->blocks.items[i]);
19,756✔
435
            for (int j = 0; j < b->ops.count; j++) {
282,887✔
436
               op_t *op = &(b->ops.items[j]);
263,131✔
437
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
263,131✔
438
                  vcode_heap_allocate(op->args.items[0]);
1,605✔
439

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

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

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

462
   case VCODE_OP_SELECT:
508✔
463
      vcode_heap_allocate(defn->args.items[1]);
508✔
464
      vcode_heap_allocate(defn->args.items[2]);
508✔
465
      break;
508✔
466

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

476
   case VCODE_OP_ALL:
477
      // Must have been allocated on the heap
478
      break;
479

480
   case VCODE_OP_NEW:
481
      // On the heap by definition
482
      break;
483

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

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

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

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

535
void vcode_unit_unref(vcode_unit_t unit)
9,735✔
536
{
537
   assert(unit != NULL);
9,735✔
538

539
   if (unit == active_unit)
9,735✔
540
      vcode_close();
9,556✔
541

542
   while (unit->children)
9,735✔
543
      vcode_unit_unref(unit->children);
×
544

545
   if (unit->context != NULL) {
9,735✔
546
      vcode_unit_t *it = &(unit->context->children);
125✔
547
      for (; *it != NULL && *it != unit; it = &((*it)->next))
389✔
548
         ;
264✔
549
      assert(*it != NULL);
125✔
550
      *it = (*it)->next;
125✔
551
   }
552

553
   for (unsigned i = 0; i < unit->blocks.count; i++) {
19,574✔
554
      block_t *b = &(unit->blocks.items[i]);
9,839✔
555

556
      for (unsigned j = 0; j < b->ops.count; j++) {
69,112✔
557
         op_t *o = &(b->ops.items[j]);
59,273✔
558
         if (OP_HAS_COMMENT(o->kind))
59,273✔
559
            free(o->comment);
470✔
560
         if (OP_HAS_TARGET(o->kind))
59,273✔
561
            free(o->targets.items);
77✔
562
         free(o->args.items);
59,273✔
563
      }
564
      free(b->ops.items);
9,839✔
565
   }
566
   free(unit->blocks.items);
9,735✔
567

568
   for (unsigned i = 0; i < unit->types.count; i++) {
61,277✔
569
      vtype_t *vt = &(unit->types.items[i]);
51,542✔
570
      if (vt->kind == VCODE_TYPE_RECORD)
51,542✔
571
         free(vt->fields.items);
103✔
572
   }
573
   free(unit->types.items);
9,735✔
574

575
   free(unit->regs.items);
9,735✔
576
   free(unit->vars.items);
9,735✔
577
   free(unit->params.items);
9,735✔
578
   free(unit);
9,735✔
579
}
9,735✔
580

581
vcode_unit_t vcode_unit_next(vcode_unit_t unit)
19,294✔
582
{
583
   return unit->next;
19,294✔
584
}
585

586
vcode_unit_t vcode_unit_child(vcode_unit_t unit)
22,403✔
587
{
588
   return unit->children;
22,403✔
589
}
590

591
int vcode_count_regs(void)
33,800✔
592
{
593
   assert(active_unit != NULL);
33,800✔
594
   return active_unit->regs.count;
33,800✔
595
}
596

597
vcode_type_t vcode_reg_type(vcode_reg_t reg)
4,170,720✔
598
{
599
   return vcode_reg_data(reg)->type;
4,170,720✔
600
}
601

602
vtype_kind_t vcode_reg_kind(vcode_reg_t reg)
1,107,870✔
603
{
604
   return vtype_kind(vcode_reg_type(reg));
1,107,870✔
605
}
606

607
vcode_type_t vcode_reg_bounds(vcode_reg_t reg)
182,256✔
608
{
609
   return vcode_reg_data(reg)->bounds;
182,256✔
610
}
611

612
bool vcode_reg_const(vcode_reg_t reg, int64_t *value)
737,323✔
613
{
614
   reg_t *r = vcode_reg_data(reg);
737,323✔
615

616
   vtype_kind_t kind = vtype_kind(r->type);
737,323✔
617
   if (kind != VCODE_TYPE_INT && kind != VCODE_TYPE_OFFSET)
737,323✔
618
      return false;
619

620
   vtype_t *bounds = vcode_type_data(r->bounds);
722,130✔
621

622
   VCODE_ASSERT(
722,130✔
623
      bounds->kind == VCODE_TYPE_INT || bounds->kind == VCODE_TYPE_OFFSET,
624
      "integer register r%d has non-integer bounds", reg);
625

626
   if (bounds->low == bounds->high) {
722,130✔
627
      if (value) *value = bounds->low;
452,186✔
628
      return true;
452,186✔
629
   }
630
   else
631
      return false;
632
}
633

634
void vcode_opt(void)
35,707✔
635
{
636
   // Prune assignments to unused registers
637

638
   int *uses LOCAL = xmalloc_array(active_unit->regs.count, sizeof(int));
71,414✔
639

640
   int pruned = 0;
35,707✔
641
   do {
55,565✔
642
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
55,565✔
643
      pruned = 0;
55,565✔
644

645
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
264,294✔
646
         block_t *b = &(active_unit->blocks.items[i]);
208,729✔
647

648
         for (int j = b->ops.count - 1; j >= 0; j--) {
2,893,800✔
649
            op_t *o = &(b->ops.items[j]);
2,685,070✔
650

651
            switch (o->kind) {
2,685,070✔
652
            case VCODE_OP_FCALL:
59,024✔
653
               if (o->result == VCODE_INVALID_REG)
59,024✔
654
                  break;
655
            case VCODE_OP_CONST:
656
            case VCODE_OP_CONST_REAL:
657
            case VCODE_OP_CONST_ARRAY:
658
            case VCODE_OP_CONST_RECORD:
659
            case VCODE_OP_CONST_REP:
660
            case VCODE_OP_LOAD:
661
            case VCODE_OP_LOAD_INDIRECT:
662
            case VCODE_OP_VAR_UPREF:
663
            case VCODE_OP_ADD:
664
            case VCODE_OP_ARRAY_REF:
665
            case VCODE_OP_SUB:
666
            case VCODE_OP_MUL:
667
            case VCODE_OP_CMP:
668
            case VCODE_OP_INDEX:
669
            case VCODE_OP_WRAP:
670
            case VCODE_OP_EXP:
671
            case VCODE_OP_UNDEFINED:
672
            case VCODE_OP_UARRAY_LEN:
673
            case VCODE_OP_UARRAY_DIR:
674
            case VCODE_OP_UARRAY_LEFT:
675
            case VCODE_OP_UARRAY_RIGHT:
676
            case VCODE_OP_UNWRAP:
677
            case VCODE_OP_NULL:
678
            case VCODE_OP_ADDRESS_OF:
679
            case VCODE_OP_RANGE_NULL:
680
            case VCODE_OP_RANGE_LENGTH:
681
            case VCODE_OP_DEBUG_LOCUS:
682
            case VCODE_OP_SELECT:
683
            case VCODE_OP_CAST:
684
            case VCODE_OP_RESOLVED:
685
            case VCODE_OP_TRAP_ADD:
686
            case VCODE_OP_TRAP_SUB:
687
            case VCODE_OP_TRAP_MUL:
688
            case VCODE_OP_TRAP_EXP:
689
            case VCODE_OP_ALLOC:
690
               if (uses[o->result] == -1) {
1,791,620✔
691
                  vcode_dump_with_mark(j, NULL, NULL);
×
692
                  fatal("defintion of r%d does not dominate all uses",
×
693
                        o->result);
694
               }
695
               else if (uses[o->result] == 0) {
1,791,620✔
696
                  if (false DEBUG_ONLY(|| o->kind != VCODE_OP_CONST)) {
173,546✔
697
                     o->comment = xasprintf("Dead %s definition of r%d",
52,131✔
698
                                            vcode_op_string(o->kind),
699
                                            o->result);
700
                     o->kind = VCODE_OP_COMMENT;
52,131✔
701
                  }
702
                  else
703
                     o->kind = (vcode_op_t)-1;
121,415✔
704
                  vcode_reg_array_resize(&(o->args), 0, VCODE_INVALID_REG);
173,546✔
705
                  pruned++;
173,546✔
706
               }
707
               uses[o->result] = -1;
1,791,620✔
708
               break;
1,791,620✔
709

710
            default:
711
               break;
712
            }
713

714
            for (int k = 0; k < o->args.count; k++) {
7,307,820✔
715
               if (o->args.items[k] != VCODE_INVALID_REG)
4,622,750✔
716
                  uses[o->args.items[k]]++;
4,575,740✔
717
            }
718
         }
719
      }
720
   } while (pruned > 0);
55,565✔
721

722
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
153,035✔
723
      block_t *b = &(active_unit->blocks.items[i]);
117,328✔
724
      op_t *dst = &(b->ops.items[0]);
117,328✔
725
      size_t copied = 0;
117,328✔
726
      for (int j = 0; j < b->ops.count; j++) {
1,550,630✔
727
         const op_t *src = &(b->ops.items[j]);
1,433,300✔
728
         if (src->kind != (vcode_op_t)-1) {
1,433,300✔
729
            if (src != dst) {
1,311,890✔
730
               assert(dst < src);
495,650✔
731
               *dst = *src;
495,650✔
732
            }
733
            dst++;
1,311,890✔
734
            copied++;
1,311,890✔
735
         }
736
      }
737

738
      assert(copied <= b->ops.count);
117,328✔
739
      b->ops.count = copied;
117,328✔
740
   }
741
}
35,707✔
742

743
void vcode_close(void)
18,205✔
744
{
745
   active_unit  = NULL;
18,205✔
746
   active_block = -1;
18,205✔
747
}
18,205✔
748

749
int vcode_count_blocks(void)
101,147✔
750
{
751
   assert(active_unit != NULL);
101,147✔
752
   return active_unit->blocks.count;
101,147✔
753
}
754

755
int vcode_count_ops(void)
390,603✔
756
{
757
   assert(active_unit != NULL);
390,603✔
758
   assert(active_block != VCODE_INVALID_BLOCK);
390,603✔
759
   return active_unit->blocks.items[active_block].ops.count;
390,603✔
760
}
761

762
int vcode_count_vars(void)
67,612✔
763
{
764
   assert(active_unit != NULL);
67,612✔
765
   return active_unit->vars.count;
67,612✔
766
}
767

768
vcode_var_t vcode_find_var(ident_t name)
13✔
769
{
770
   assert(active_unit != NULL);
13✔
771
   for (int i = 0; i < active_unit->vars.count; i++) {
22✔
772
      if (active_unit->vars.items[i].name == name)
10✔
773
         return i;
1✔
774
   }
775

776
   return VCODE_INVALID_VAR;
777
}
778

779
ident_t vcode_var_name(vcode_var_t var)
29,090✔
780
{
781
   return vcode_var_data(var)->name;
29,090✔
782
}
783

784
vcode_type_t vcode_var_type(vcode_var_t var)
120,269✔
785
{
786
   return vcode_var_data(var)->type;
120,269✔
787
}
788

789
vcode_type_t vcode_var_bounds(vcode_var_t var)
3,098✔
790
{
791
   return vcode_var_data(var)->bounds;
3,098✔
792
}
793

794
vcode_var_flags_t vcode_var_flags(vcode_var_t var)
31,426✔
795
{
796
   return vcode_var_data(var)->flags;
31,426✔
797
}
798

799
vcode_op_t vcode_get_op(int op)
4,068,730✔
800
{
801
   return vcode_op_data(op)->kind;
4,068,730✔
802
}
803

804
ident_t vcode_get_func(int op)
100,383✔
805
{
806
   op_t *o = vcode_op_data(op);
100,383✔
807
   assert(OP_HAS_FUNC(o->kind));
100,383✔
808
   return o->func;
100,383✔
809
}
810

811
ident_t vcode_get_ident(int op)
79,421✔
812
{
813
   op_t *o = vcode_op_data(op);
79,421✔
814
   assert(OP_HAS_IDENT(o->kind));
79,421✔
815
   return o->ident;
79,421✔
816
}
817

818
unsigned vcode_get_subkind(int op)
83,439✔
819
{
820
   op_t *o = vcode_op_data(op);
83,439✔
821
   assert(OP_HAS_SUBKIND(o->kind));
83,439✔
822
   return o->subkind;
83,439✔
823
}
824

825
int64_t vcode_get_value(int op)
349,870✔
826
{
827
   op_t *o = vcode_op_data(op);
349,870✔
828
   assert(OP_HAS_VALUE(o->kind));
349,870✔
829
   return o->value;
349,870✔
830
}
831

832
double vcode_get_real(int op)
19,365✔
833
{
834
   op_t *o = vcode_op_data(op);
19,365✔
835
   assert(OP_HAS_REAL(o->kind));
19,365✔
836
   return o->real;
19,365✔
837
}
838

839
vcode_var_t vcode_get_address(int op)
123,528✔
840
{
841
   op_t *o = vcode_op_data(op);
123,528✔
842
   assert(OP_HAS_ADDRESS(o->kind));
123,528✔
843
   return o->address;
123,528✔
844
}
845

846
unsigned vcode_get_dim(int op)
55,702✔
847
{
848
   op_t *o = vcode_op_data(op);
55,702✔
849
   assert(OP_HAS_DIM(o->kind));
55,702✔
850
   return o->dim;
55,702✔
851
}
852

853
int vcode_get_hops(int op)
46,899✔
854
{
855
   op_t *o = vcode_op_data(op);
46,899✔
856
   assert(OP_HAS_HOPS(o->kind));
46,899✔
857
   return o->hops;
46,899✔
858
}
859

860
int vcode_get_field(int op)
25,873✔
861
{
862
   op_t *o = vcode_op_data(op);
25,873✔
863
   assert(OP_HAS_FIELD(o->kind));
25,873✔
864
   return o->field;
25,873✔
865
}
866

867
vcode_var_t vcode_get_type(int op)
13,745✔
868
{
869
   op_t *o = vcode_op_data(op);
13,745✔
870
   assert(OP_HAS_TYPE(o->kind));
13,745✔
871
   return o->type;
13,745✔
872
}
873

874
int vcode_count_args(int op)
164,554✔
875
{
876
   return vcode_op_data(op)->args.count;
164,554✔
877
}
878

879
vcode_reg_t vcode_get_arg(int op, int arg)
2,519,010✔
880
{
881
   op_t *o = vcode_op_data(op);
2,519,010✔
882
   return vcode_reg_array_nth(&(o->args), arg);
2,519,010✔
883
}
884

885
vcode_reg_t vcode_get_result(int op)
973,136✔
886
{
887
   op_t *o = vcode_op_data(op);
973,136✔
888
   return o->result;
973,136✔
889
}
890

891
vcode_cmp_t vcode_get_cmp(int op)
29,287✔
892
{
893
   op_t *o = vcode_op_data(op);
29,287✔
894
   assert(OP_HAS_CMP(o->kind));
29,287✔
895
   return o->cmp;
29,287✔
896
}
897

898
uint32_t vcode_get_tag(int op)
1,593✔
899
{
900
   op_t *o = vcode_op_data(op);
1,593✔
901
   assert(OP_HAS_TAG(o->kind));
1,593✔
902
   return o->tag;
1,593✔
903
}
904

905
const loc_t *vcode_get_loc(int op)
1,233,310✔
906
{
907
   op_t *o = vcode_op_data(op);
1,233,310✔
908
   return &(o->loc);
1,233,310✔
909
}
910

911
vcode_block_t vcode_get_target(int op, int nth)
126,393✔
912
{
913
   op_t *o = vcode_op_data(op);
126,393✔
914
   assert(OP_HAS_TARGET(o->kind));
126,393✔
915
   return vcode_block_array_nth(&(o->targets), nth);
126,393✔
916
}
917

918
bool vcode_block_empty(void)
×
919
{
920
   assert(active_unit != NULL);
×
921
   assert(active_block != VCODE_INVALID_BLOCK);
×
922

923
   return active_unit->blocks.items[active_block].ops.count == 0;
×
924
}
925

926
bool vcode_block_finished(void)
1,528,260✔
927
{
928
   assert(active_unit != NULL);
1,528,260✔
929
   assert(active_block != VCODE_INVALID_BLOCK);
1,528,260✔
930

931
   const block_t *b = &(active_unit->blocks.items[active_block]);
1,528,260✔
932
   if (b->ops.count == 0)
1,528,260✔
933
      return false;
934
   else {
935
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,371,010✔
936
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,371,010✔
937
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,370,990✔
938
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
1,370,990✔
939
         || kind == VCODE_OP_UNREACHABLE;
4,102,220✔
940
   }
941
}
942

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

976
LCOV_EXCL_START
977
static int vcode_dump_reg(vcode_reg_t reg)
978
{
979
   int printed;
980
   if (reg == VCODE_INVALID_REG)
981
      printed = color_printf("$red$invalid$$");
982
   else
983
      printed = color_printf("$green$r%d$$", reg);
984

985
   if (dump_callback != NULL)
986
      printed += (*dump_callback)(VCODE_DUMP_REG, reg, dump_arg);
987

988
   return printed;
989
}
990

991
static int vcode_pretty_print_int(int64_t n)
992
{
993
   if (n == INT64_MAX)
994
      return printf("2^63-1");
995
   else if (n == INT64_MIN)
996
      return printf("-2^63");
997
   else if (n == INT32_MAX)
998
      return printf("2^31-1");
999
   else if (n == INT32_MIN)
1000
      return printf("-2^31");
1001
   else
1002
      return printf("%"PRIi64, n);
1003
}
1004

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

1020
   case VCODE_TYPE_REAL:
1021
      if (vt->rlow == -DBL_MAX && vt->rhigh == DBL_MAX)
1022
         col += printf("%%");
1023
      else if (vt->rlow == vt->rhigh)
1024
         col += printf("%f", vt->rlow);
1025
      else
1026
         col += printf("%f..%f", vt->rlow, vt->rhigh);
1027
      break;
1028

1029
   case VCODE_TYPE_CARRAY:
1030
      {
1031
         col += printf("[%u] : ", vt->size);
1032
         col += vcode_dump_one_type(vt->elem);
1033
         if (!vtype_eq(vt->elem, vt->bounds)) {
1034
            col += printf(" => ");
1035
            col += vcode_dump_one_type(vt->bounds);
1036
         }
1037
      }
1038
      break;
1039

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

1054
   case VCODE_TYPE_POINTER:
1055
      col += printf("@<");
1056
      col += vcode_dump_one_type(vt->pointed);
1057
      col += printf(">");
1058
      break;
1059

1060
   case VCODE_TYPE_ACCESS:
1061
      col += printf("A<");
1062
      col += vcode_dump_one_type(vt->pointed);
1063
      col += printf(">");
1064
      break;
1065

1066
   case VCODE_TYPE_SIGNAL:
1067
      col += printf("$<");
1068
      col += vcode_dump_one_type(vt->base);
1069
      col += printf(">");
1070
      break;
1071

1072
   case VCODE_TYPE_OFFSET:
1073
      col += printf("#");
1074
      break;
1075

1076
   case VCODE_TYPE_RECORD:
1077
      col += printf("%s{}", istr(vt->name));
1078
      break;
1079

1080
   case VCODE_TYPE_FILE:
1081
      col += printf("F<");
1082
      col += vcode_dump_one_type(vt->base);
1083
      col += printf(">");
1084
      break;
1085

1086
   case VCODE_TYPE_OPAQUE:
1087
      col += printf("?");
1088
      break;
1089

1090
   case VCODE_TYPE_RESOLUTION:
1091
      col += printf("R<");
1092
      col += vcode_dump_one_type(vt->base);
1093
      col += printf(">");
1094
      break;
1095

1096
   case VCODE_TYPE_CLOSURE:
1097
      col += printf("C<");
1098
      col += vcode_dump_one_type(vt->base);
1099
      col += printf(">");
1100
      break;
1101

1102
   case VCODE_TYPE_CONTEXT:
1103
      col += printf("P<%s>", istr(vt->name));
1104
      break;
1105

1106
   case VCODE_TYPE_DEBUG_LOCUS:
1107
      col += printf("D<>");
1108
      break;
1109

1110
   case VCODE_TYPE_TRIGGER:
1111
      col += printf("T<>");
1112
      break;
1113
   }
1114

1115
   return col;
1116
}
1117

1118
static void vcode_dump_tab(int col, int to_col)
1119
{
1120
   if (col >= to_col)
1121
      printf(" ");
1122
   else {
1123
      while (col < to_col)
1124
         col += printf(" ");
1125
   }
1126
}
1127

1128
static void vcode_dump_comment(int col)
1129
{
1130
   vcode_dump_tab(col, 40);
1131
   color_printf("$cyan$// ");
1132
}
1133

1134
static void vcode_dump_type(int col, vcode_type_t type, vcode_type_t bounds)
1135
{
1136
   vcode_dump_comment(col);
1137
   vcode_dump_one_type(type);
1138
   if (!vtype_eq(type, bounds)) {
1139
      printf(" => ");
1140
      vcode_dump_one_type(bounds);
1141
   }
1142
}
1143

1144
static void vcode_dump_result_type(int col, const op_t *op)
1145
{
1146
   if (op->result != VCODE_INVALID_REG) {
1147
      reg_t *r = vcode_reg_data(op->result);
1148
      vcode_dump_type(col, r->type, r->bounds);
1149
   }
1150
}
1151

1152
static int vcode_dump_var(vcode_var_t var, int hops)
1153
{
1154
   vcode_unit_t owner = active_unit;
1155
   while (owner && hops--)
1156
      owner = owner->context;
1157

1158
   if (owner == NULL || var >= owner->vars.count)
1159
      return color_printf("$red$invalid$$");
1160
   else {
1161
      var_t *v = var_array_nth_ptr(&(owner->vars), var);
1162
      return color_printf("$magenta$%s$$", istr(v->name));
1163
   }
1164
}
1165

1166
void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg)
1167
{
1168
   assert(active_unit != NULL);
1169

1170
   dump_callback = callback;
1171
   dump_arg = arg;
1172

1173
   const vcode_unit_t vu = active_unit;
1174
   vcode_block_t old_block = active_block;
1175

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

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

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

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

1231
   if (vu->result != VCODE_INVALID_TYPE) {
1232
      color_printf("Result     $cyan$");
1233
      vcode_dump_one_type(vu->result);
1234
      color_printf("$$\n");
1235
   }
1236

1237
   if (vu->kind == VCODE_UNIT_FUNCTION
1238
       || vu->kind == VCODE_UNIT_PROCEDURE
1239
       || vu->kind == VCODE_UNIT_PROPERTY
1240
       || (vu->kind == VCODE_UNIT_PROTECTED && vu->params.count > 0)) {
1241

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

1244
      for (size_t i = 0; i < vu->params.count; i++) {
1245
         const param_t *p = &(vu->params.items[i]);
1246
         int col = printf("  ");
1247
         col += vcode_dump_reg(p->reg);
1248
         while (col < (dump_callback ? 12 : 8))
1249
            col += printf(" ");
1250
         col += color_printf("$magenta$%s$$", istr(p->name));
1251
         vcode_dump_type(col, p->type, p->bounds);
1252
         color_printf("$$\n");
1253
      }
1254
   }
1255

1256
   printf("Begin\n");
1257
   for (int i = 0; i < vu->blocks.count; i++) {
1258
      active_block = i;
1259
      const block_t *b = &(vu->blocks.items[i]);
1260
      for (int j = 0; j < b->ops.count; j++) {
1261
         int col = 0;
1262
         if (j == 0)
1263
            col += color_printf("  $yellow$%2d:$$ ", i);
1264
         else
1265
            col += printf("      ");
1266

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

1286
         case VCODE_OP_CONST:
1287
            {
1288
               col += vcode_dump_reg(op->result);
1289
               col += printf(" := %s %"PRIi64"",
1290
                             vcode_op_string(op->kind),
1291
                             op->value);
1292
               vcode_dump_result_type(col, op);
1293
            }
1294
            break;
1295

1296
         case VCODE_OP_CONST_REAL:
1297
            {
1298
               col += vcode_dump_reg(op->result);
1299
               col += printf(" := %s %g",
1300
                             vcode_op_string(op->kind),
1301
                             op->real);
1302
               vcode_dump_result_type(col, op);
1303
            }
1304
            break;
1305

1306
         case VCODE_OP_ALLOC:
1307
            {
1308
               col += vcode_dump_reg(op->result);
1309
               col += printf(" := %s ", vcode_op_string(op->kind));
1310
               col += vcode_dump_reg(op->args.items[0]);
1311
               vcode_dump_result_type(col, op);
1312
            }
1313
            break;
1314

1315
         case VCODE_OP_FCALL:
1316
            {
1317
               if (op->result != VCODE_INVALID_REG) {
1318
                  col += vcode_dump_reg(op->result);
1319
                  col += printf(" := ");
1320
               }
1321
               if (op->subkind == VCODE_CC_FOREIGN)
1322
                  col += printf("foreign ");
1323
               else if (op->subkind == VCODE_CC_VARIADIC)
1324
                  col += printf("variadic ");
1325
               col += color_printf("%s $magenta$%s$$ ",
1326
                                   vcode_op_string(op->kind),
1327
                                   istr(op->func));
1328
               for (int i = 0; i < op->args.count; i++) {
1329
                  if (i > 0)
1330
                     col += printf(", ");
1331
                  col += vcode_dump_reg(op->args.items[i]);
1332
               }
1333
               vcode_dump_result_type(col, op);
1334
            }
1335
            break;
1336

1337
         case VCODE_OP_MAP_CONST:
1338
            {
1339
               printf("%s ", vcode_op_string(op->kind));
1340
               vcode_dump_reg(op->args.items[0]);
1341
               printf(" to ");
1342
               vcode_dump_reg(op->args.items[1]);
1343
               printf(" count ");
1344
               vcode_dump_reg(op->args.items[2]);
1345
            }
1346
            break;
1347

1348
         case VCODE_OP_MAP_SIGNAL:
1349
            {
1350
               printf("%s ", vcode_op_string(op->kind));
1351
               vcode_dump_reg(op->args.items[0]);
1352
               printf(" to ");
1353
               vcode_dump_reg(op->args.items[1]);
1354
               if (op->args.items[2] == op->args.items[3]) {
1355
                  printf(" count ");
1356
                  vcode_dump_reg(op->args.items[2]);
1357
               }
1358
               else {
1359
                  printf(" src count ");
1360
                  vcode_dump_reg(op->args.items[2]);
1361
                  printf(" dst count ");
1362
                  vcode_dump_reg(op->args.items[3]);
1363
               }
1364
               if (op->args.count > 4) {
1365
                  printf(" conv ");
1366
                  vcode_dump_reg(op->args.items[4]);
1367
               }
1368
            }
1369
            break;
1370

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

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

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

1404
         case VCODE_OP_PUSH_SCOPE:
1405
            {
1406
               printf("%s locus ", vcode_op_string(op->kind));
1407
               vcode_dump_reg(op->args.items[0]);
1408
            }
1409
            break;
1410

1411
         case VCODE_OP_POP_SCOPE:
1412
            {
1413
               printf("%s", vcode_op_string(op->kind));
1414
            }
1415
            break;
1416

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

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

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

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

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

1498
         case VCODE_OP_PROCESS_INIT:
1499
            {
1500
               color_printf("%s $magenta$%s$$ locus ",
1501
                            vcode_op_string(op->kind), istr(op->func));
1502
               vcode_dump_reg(op->args.items[0]);
1503
            }
1504
            break;
1505

1506
         case VCODE_OP_PROTECTED_FREE:
1507
            {
1508
               printf("%s ", vcode_op_string(op->kind));
1509
               vcode_dump_reg(op->args.items[0]);
1510
            }
1511
            break;
1512

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

1524
         case VCODE_OP_JUMP:
1525
            {
1526
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1527
                            op->targets.items[0]);
1528
            }
1529
            break;
1530

1531
         case VCODE_OP_COND:
1532
            {
1533
               printf("%s ", vcode_op_string(op->kind));
1534
               vcode_dump_reg(op->args.items[0]);
1535
               color_printf(" then $yellow$%d$$ else $yellow$%d$$",
1536
                            op->targets.items[0], op->targets.items[1]);
1537
            }
1538
            break;
1539

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

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

1576
         case VCODE_OP_LOAD:
1577
            {
1578
               col += vcode_dump_reg(op->result);
1579
               col += printf(" := %s ", vcode_op_string(op->kind));
1580
               col += vcode_dump_var(op->address, 0);
1581
               vcode_dump_result_type(col, op);
1582
            }
1583
            break;
1584

1585
         case VCODE_OP_LOAD_INDIRECT:
1586
            {
1587
               col += vcode_dump_reg(op->result);
1588
               col += color_printf(" := %s ", vcode_op_string(op->kind));
1589
               col += vcode_dump_reg(op->args.items[0]);
1590
               vcode_dump_result_type(col, op);
1591
            }
1592
            break;
1593

1594
         case VCODE_OP_STORE:
1595
            {
1596
               vcode_dump_var(op->address, 0);
1597
               printf(" := %s ", vcode_op_string(op->kind));
1598
               vcode_dump_reg(op->args.items[0]);
1599
            }
1600
            break;
1601

1602
         case VCODE_OP_STORE_INDIRECT:
1603
            {
1604
               vcode_dump_reg(op->args.items[1]);
1605
               printf(" := %s ", vcode_op_string(op->kind));
1606
               vcode_dump_reg(op->args.items[0]);
1607
            }
1608
            break;
1609

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

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

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

1683
         case VCODE_OP_NOT:
1684
            {
1685
               col += vcode_dump_reg(op->result);
1686
               col += printf(" := %s ", vcode_op_string(op->kind));
1687
               col += vcode_dump_reg(op->args.items[0]);
1688
               vcode_dump_result_type(col, op);
1689
            }
1690
            break;
1691

1692
         case VCODE_OP_COMMENT:
1693
            {
1694
               color_printf("$cyan$// %s$$ ", op->comment);
1695
            }
1696
            break;
1697

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

1710
               putchar(op->kind == VCODE_OP_CONST_ARRAY ? ']' : '}');
1711
               vcode_dump_result_type(col + 1, op);
1712
            }
1713
            break;
1714

1715
         case VCODE_OP_CONST_REP:
1716
            {
1717
               col += vcode_dump_reg(op->result);
1718
               col += printf(" := const [");
1719
               col += vcode_dump_reg(op->args.items[0]);
1720
               col += printf("]*%"PRIi64, op->value);
1721
               vcode_dump_result_type(col, op);
1722
            }
1723
            break;
1724

1725
         case VCODE_OP_ADDRESS_OF:
1726
         case VCODE_OP_CAST:
1727
            {
1728
               col += vcode_dump_reg(op->result);
1729
               col += printf(" := %s ", vcode_op_string(op->kind));
1730
               col += vcode_dump_reg(op->args.items[0]);
1731
               vcode_dump_result_type(col, op);
1732
            }
1733
            break;
1734

1735
         case VCODE_OP_RETURN:
1736
            {
1737
               printf("%s ", vcode_op_string(op->kind));
1738
               if (op->args.count > 0)
1739
                  vcode_dump_reg(op->args.items[0]);
1740
            }
1741
            break;
1742

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

1758
         case VCODE_OP_FORCE:
1759
         case VCODE_OP_RELEASE:
1760
            {
1761
               printf("%s ", vcode_op_string(op->kind));
1762
               vcode_dump_reg(op->args.items[0]);
1763
               printf(" count ");
1764
               vcode_dump_reg(op->args.items[1]);
1765
               if (op->args.count > 2) {
1766
                  printf(" values ");
1767
                  vcode_dump_reg(op->args.items[2]);
1768
               }
1769
            }
1770
            break;
1771

1772
         case VCODE_OP_DISCONNECT:
1773
            {
1774
               printf("%s ", vcode_op_string(op->kind));
1775
               vcode_dump_reg(op->args.items[0]);
1776
               printf(" count ");
1777
               vcode_dump_reg(op->args.items[1]);
1778
               printf(" reject ");
1779
               vcode_dump_reg(op->args.items[2]);
1780
               printf(" after ");
1781
               vcode_dump_reg(op->args.items[3]);
1782
            }
1783
            break;
1784

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

1802
         case VCODE_OP_SELECT:
1803
            {
1804
               col += vcode_dump_reg(op->result);
1805
               col += printf(" := %s ", vcode_op_string(op->kind));
1806
               col += vcode_dump_reg(op->args.items[0]);
1807
               col += printf(" then ");
1808
               col += vcode_dump_reg(op->args.items[1]);
1809
               col += printf(" else ");
1810
               col += vcode_dump_reg(op->args.items[2]);
1811
               vcode_dump_result_type(col, op);
1812
            }
1813
            break;
1814

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

1835
         case VCODE_OP_UARRAY_LEFT:
1836
         case VCODE_OP_UARRAY_RIGHT:
1837
         case VCODE_OP_UARRAY_DIR:
1838
         case VCODE_OP_UARRAY_LEN:
1839
            {
1840
               col += vcode_dump_reg(op->result);
1841
               col += printf(" := %s ", vcode_op_string(op->kind));
1842
               col += vcode_dump_reg(op->args.items[0]);
1843
               col += printf(" dim %d", op->dim);
1844
               vcode_dump_result_type(col, op);
1845
            }
1846
            break;
1847

1848
         case VCODE_OP_UNWRAP:
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
               vcode_dump_result_type(col, op);
1854
            }
1855
            break;
1856

1857
         case VCODE_OP_VAR_UPREF:
1858
            {
1859
               col += vcode_dump_reg(op->result);
1860
               col += printf(" := %s %d, ", vcode_op_string(op->kind),
1861
                             op->hops);
1862
               col += vcode_dump_var(op->address, op->hops);
1863
               vcode_dump_result_type(col, op);
1864
            }
1865
            break;
1866

1867
         case VCODE_OP_CONTEXT_UPREF:
1868
            {
1869
               col += vcode_dump_reg(op->result);
1870
               col += printf(" := %s %d", vcode_op_string(op->kind), op->hops);
1871
               vcode_dump_result_type(col, op);
1872
            }
1873
            break;
1874

1875
         case VCODE_OP_ACTIVE:
1876
         case VCODE_OP_EVENT:
1877
         case VCODE_OP_DRIVING:
1878
            {
1879
               col += vcode_dump_reg(op->result);
1880
               col += printf(" := %s ", vcode_op_string(op->kind));
1881
               col += vcode_dump_reg(op->args.items[0]);
1882
               col += printf(" length ");
1883
               col += vcode_dump_reg(op->args.items[1]);
1884
               vcode_dump_result_type(col, op);
1885
            }
1886
            break;
1887

1888
         case VCODE_OP_RECORD_REF:
1889
            {
1890
               col += vcode_dump_reg(op->result);
1891
               col += printf(" := %s ", vcode_op_string(op->kind));
1892
               col += vcode_dump_reg(op->args.items[0]);
1893
               col += printf(" field %d", op->field);
1894
               vcode_dump_result_type(col, op);
1895
            }
1896
            break;
1897

1898
         case VCODE_OP_ARRAY_REF:
1899
            {
1900
               col += vcode_dump_reg(op->result);
1901
               col += printf(" := %s ", vcode_op_string(op->kind));
1902
               col += vcode_dump_reg(op->args.items[0]);
1903
               col += printf(" offset ");
1904
               col += vcode_dump_reg(op->args.items[1]);
1905
               vcode_dump_result_type(col, op);
1906
            }
1907
            break;
1908

1909
         case VCODE_OP_COPY:
1910
            {
1911
               vcode_dump_reg(op->args.items[0]);
1912
               printf(" := %s ", vcode_op_string(op->kind));
1913
               vcode_dump_reg(op->args.items[1]);
1914
               if (op->args.count > 2) {
1915
                  printf(" count " );
1916
                  vcode_dump_reg(op->args.items[2]);
1917
               }
1918
            }
1919
            break;
1920

1921
         case VCODE_OP_SCHED_EVENT:
1922
         case VCODE_OP_CLEAR_EVENT:
1923
            {
1924
               printf("%s on ", vcode_op_string(op->kind));
1925
               vcode_dump_reg(op->args.items[0]);
1926
               printf(" count ");
1927
               vcode_dump_reg(op->args.items[1]);
1928
            }
1929
            break;
1930

1931
         case VCODE_OP_IMPLICIT_EVENT:
1932
            {
1933
               printf("%s on ", vcode_op_string(op->kind));
1934
               vcode_dump_reg(op->args.items[0]);
1935
               printf(" count ");
1936
               vcode_dump_reg(op->args.items[1]);
1937
               printf(" wake ");
1938
               vcode_dump_reg(op->args.items[2]);
1939
            }
1940
            break;
1941

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

1955
         case VCODE_OP_RESUME:
1956
            {
1957
               color_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
1958
                            istr(op->func));
1959
            }
1960
            break;
1961

1962
         case VCODE_OP_MEMSET:
1963
            {
1964
               vcode_dump_reg(op->args.items[0]);
1965
               printf(" := %s ", vcode_op_string(op->kind));
1966
               vcode_dump_reg(op->args.items[1]);
1967
               printf(" length ");
1968
               vcode_dump_reg(op->args.items[2]);
1969
            }
1970
            break;
1971

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

1985
         case VCODE_OP_ENDFILE:
1986
            {
1987
               col += vcode_dump_reg(op->result);
1988
               col += printf(" := %s ", vcode_op_string(op->kind));
1989
               col += vcode_dump_reg(op->args.items[0]);
1990
               vcode_dump_result_type(col, op);
1991
            }
1992
            break;
1993

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

2011
         case VCODE_OP_FILE_CLOSE:
2012
            {
2013
               printf("%s ", vcode_op_string(op->kind));
2014
               vcode_dump_reg(op->args.items[0]);
2015
            }
2016
            break;
2017

2018
         case VCODE_OP_FILE_WRITE:
2019
            {
2020
               printf("%s ", vcode_op_string(op->kind));
2021
               vcode_dump_reg(op->args.items[0]);
2022
               printf(" value ");
2023
               vcode_dump_reg(op->args.items[1]);
2024
               if (op->args.count == 3) {
2025
                  printf(" length ");
2026
                  vcode_dump_reg(op->args.items[2]);
2027
               }
2028
            }
2029
            break;
2030

2031
         case VCODE_OP_FILE_READ:
2032
            {
2033
               printf("%s ", vcode_op_string(op->kind));
2034
               vcode_dump_reg(op->args.items[0]);
2035
               printf(" ptr ");
2036
               vcode_dump_reg(op->args.items[1]);
2037
               if (op->args.count >= 3) {
2038
                  printf(" inlen ");
2039
                  vcode_dump_reg(op->args.items[2]);
2040
                  if (op->args.count >= 4) {
2041
                     printf(" outlen ");
2042
                     vcode_dump_reg(op->args.items[3]);
2043
                  }
2044
               }
2045
            }
2046
            break;
2047

2048
         case VCODE_OP_NULL:
2049
         case VCODE_OP_NEW:
2050
            {
2051
               col += vcode_dump_reg(op->result);
2052
               col += printf(" := %s", vcode_op_string(op->kind));
2053
               if (op->args.count == 1) {
2054
                  col += printf(" length ");
2055
                  col += vcode_dump_reg(op->args.items[0]);
2056
               }
2057
               vcode_dump_result_type(col, op);
2058
            }
2059
            break;
2060

2061
         case VCODE_OP_NULL_CHECK:
2062
            {
2063
               col += printf("%s ", vcode_op_string(op->kind));
2064
               col += vcode_dump_reg(op->args.items[0]);
2065
               col += printf(" locus ");
2066
               col += vcode_dump_reg(op->args.items[1]);
2067
            }
2068
            break;
2069

2070
         case VCODE_OP_DEALLOCATE:
2071
            {
2072
               col += printf("%s ", vcode_op_string(op->kind));
2073
               col += vcode_dump_reg(op->args.items[0]);
2074
            }
2075
            break;
2076

2077
         case VCODE_OP_ALL:
2078
            {
2079
               col += vcode_dump_reg(op->result);
2080
               col += printf(" := %s ", vcode_op_string(op->kind));
2081
               col += vcode_dump_reg(op->args.items[0]);
2082
               vcode_dump_result_type(col, op);
2083
            }
2084
            break;
2085

2086
         case VCODE_OP_LAST_EVENT:
2087
         case VCODE_OP_LAST_ACTIVE:
2088
         case VCODE_OP_DRIVING_VALUE:
2089
            {
2090
               col += vcode_dump_reg(op->result);
2091
               col += printf(" := %s ", vcode_op_string(op->kind));
2092
               col += vcode_dump_reg(op->args.items[0]);
2093
               if (op->args.count > 1) {
2094
                  col += printf(" length ");
2095
                  col += vcode_dump_reg(op->args.items[1]);
2096
               }
2097
               vcode_dump_result_type(col, op);
2098
            }
2099
            break;
2100

2101
         case VCODE_OP_ALIAS_SIGNAL:
2102
            {
2103
               printf("%s ", vcode_op_string(op->kind));
2104
               vcode_dump_reg(op->args.items[0]);
2105
               printf(" locus ");
2106
               vcode_dump_reg(op->args.items[1]);
2107
            }
2108
            break;
2109

2110
         case VCODE_OP_LENGTH_CHECK:
2111
            {
2112
               col += printf("%s left ", vcode_op_string(op->kind));
2113
               col += vcode_dump_reg(op->args.items[0]);
2114
               col += printf(" == right ");
2115
               col += vcode_dump_reg(op->args.items[1]);
2116
               col += printf(" locus ");
2117
               col += vcode_dump_reg(op->args.items[2]);
2118
               if (op->args.count > 3) {
2119
                  col += printf(" dim ");
2120
                  col += vcode_dump_reg(op->args.items[3]);
2121
               }
2122
            }
2123
            break;
2124

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

2135
         case VCODE_OP_INDEX_CHECK:
2136
         case VCODE_OP_RANGE_CHECK:
2137
            {
2138
               col += printf("%s ", vcode_op_string(op->kind));
2139
               col += vcode_dump_reg(op->args.items[0]);
2140
               col += printf(" left ");
2141
               col += vcode_dump_reg(op->args.items[1]);
2142
               col += printf(" right ");
2143
               col += vcode_dump_reg(op->args.items[2]);
2144
               col += printf(" dir ");
2145
               col += vcode_dump_reg(op->args.items[3]);
2146
               col += printf(" locus ");
2147
               col += vcode_dump_reg(op->args.items[4]);
2148
               if (op->args.items[5] != op->args.items[4]) {
2149
                  col += printf(" hint ");
2150
                  col += vcode_dump_reg(op->args.items[5]);
2151
               }
2152
            }
2153
            break;
2154

2155
         case VCODE_OP_DEBUG_OUT:
2156
            {
2157
               col += printf("%s ", vcode_op_string(op->kind));
2158
               col += vcode_dump_reg(op->args.items[0]);
2159
            }
2160
            break;
2161

2162
         case VCODE_OP_COVER_STMT:
2163
            {
2164
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2165
            }
2166
            break;
2167

2168
         case VCODE_OP_COVER_TOGGLE:
2169
         case VCODE_OP_COVER_BRANCH:
2170
         case VCODE_OP_COVER_EXPR:
2171
         case VCODE_OP_COVER_STATE:
2172
            {
2173
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2174
               vcode_dump_reg(op->args.items[0]);
2175
            }
2176
            break;
2177

2178
         case VCODE_OP_UNDEFINED:
2179
            {
2180
               col += vcode_dump_reg(op->result);
2181
               col += printf(" := %s", vcode_op_string(op->kind));
2182
               vcode_dump_result_type(col, op);
2183
            }
2184
            break;
2185

2186
         case VCODE_OP_RANGE_LENGTH:
2187
         case VCODE_OP_RANGE_NULL:
2188
            {
2189
               col += vcode_dump_reg(op->result);
2190
               col += printf(" := %s left ", vcode_op_string(op->kind));
2191
               vcode_dump_reg(op->args.items[0]);
2192
               col += printf(" right ");
2193
               vcode_dump_reg(op->args.items[1]);
2194
               col += printf(" dir ");
2195
               col += vcode_dump_reg(op->args.items[2]);
2196
               vcode_dump_result_type(col, op);
2197
            }
2198
            break;
2199

2200
         case VCODE_OP_LINK_PACKAGE:
2201
         case VCODE_OP_LINK_INSTANCE:
2202
            {
2203
               col += vcode_dump_reg(op->result);
2204
               col += color_printf(" := %s $magenta$%s$$",
2205
                                   vcode_op_string(op->kind), istr(op->ident));
2206
               if (op->args.count > 0) {
2207
                  col += printf(" locus ");
2208
                  col += vcode_dump_reg(op->args.items[0]);
2209
               }
2210
               vcode_dump_result_type(col, op);
2211
            }
2212
            break;
2213

2214
         case VCODE_OP_LINK_VAR:
2215
            {
2216
               col += vcode_dump_reg(op->result);
2217
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2218
               col += vcode_dump_reg(op->args.items[0]);
2219
               col += color_printf(" $magenta$%s$$", istr(op->ident));
2220
               vcode_dump_result_type(col, op);
2221
            }
2222
            break;
2223

2224
         case VCODE_OP_UNREACHABLE:
2225
            {
2226
               printf("%s", vcode_op_string(op->kind));
2227
               if (op->args.count > 0) {
2228
                  printf(" ");
2229
                  vcode_dump_reg(op->args.items[0]);
2230
               }
2231
            }
2232
            break;
2233

2234
         case VCODE_OP_DEBUG_LOCUS:
2235
            {
2236
               col += vcode_dump_reg(op->result);
2237
               col += color_printf(" := %s $magenta$%s$$%+"PRIi64,
2238
                                   vcode_op_string(op->kind),
2239
                                   istr(op->ident), op->value);
2240
               vcode_dump_result_type(col, op);
2241
            }
2242
            break;
2243

2244
         case VCODE_OP_ENTER_STATE:
2245
            {
2246
               printf("%s ", vcode_op_string(op->kind));
2247
               vcode_dump_reg(op->args.items[0]);
2248
            }
2249
            break;
2250

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

2268
         case VCODE_OP_REFLECT_SUBTYPE:
2269
            {
2270
               col += vcode_dump_reg(op->result);
2271
               col += printf(" := %s ", vcode_op_string(op->kind));
2272
               col += printf(" context ");
2273
               vcode_dump_reg(op->args.items[0]);
2274
               col += printf(" locus ");
2275
               col += vcode_dump_reg(op->args.items[1]);
2276
               if (op->args.count > 2) {
2277
                  col += printf(" bounds ");
2278
                  col += vcode_dump_reg(op->args.items[2]);
2279
               }
2280
               vcode_dump_result_type(col, op);
2281
            }
2282
            break;
2283

2284
         case VCODE_OP_FUNCTION_TRIGGER:
2285
            {
2286
               col += vcode_dump_reg(op->result);
2287
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2288
               col += vcode_dump_reg(op->args.items[0]);
2289
               vcode_dump_result_type(col, op);
2290
            }
2291
            break;
2292

2293
         case VCODE_OP_ADD_TRIGGER:
2294
            {
2295
               printf("%s ", vcode_op_string(op->kind));
2296
               vcode_dump_reg(op->args.items[0]);
2297
            }
2298
            break;
2299
         }
2300

2301
         if (j == mark_op && i == old_block)
2302
            color_printf("\t $red$<----$$");
2303

2304
         color_printf("$$\n");
2305

2306
         if (callback != NULL)
2307
            (*callback)(VCODE_DUMP_OP, j, arg);
2308
      }
2309

2310
      if (b->ops.count == 0)
2311
         color_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2312
   }
2313

2314
   printf("\n");
2315
   fflush(stdout);
2316

2317
   active_block = old_block;
2318
}
2319
LCOV_EXCL_STOP
2320

2321
bool vtype_eq(vcode_type_t a, vcode_type_t b)
29,269,200✔
2322
{
2323
   assert(active_unit != NULL);
29,682,300✔
2324

2325
   if (a == b)
29,682,300✔
2326
      return true;
2327
   else {
2328
      const vtype_t *at = vcode_type_data(a);
27,222,700✔
2329
      const vtype_t *bt = vcode_type_data(b);
27,222,700✔
2330

2331
      if (at->kind != bt->kind)
27,222,700✔
2332
         return false;
2333

2334
      switch (at->kind) {
12,416,200✔
2335
      case VCODE_TYPE_INT:
10,606,800✔
2336
         return (at->low == bt->low) && (at->high == bt->high);
19,979,400✔
2337
      case VCODE_TYPE_REAL:
913,333✔
2338
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
1,778,490✔
2339
      case VCODE_TYPE_CARRAY:
80,855✔
2340
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
87,063✔
2341
      case VCODE_TYPE_UARRAY:
72,126✔
2342
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
87,133✔
2343
      case VCODE_TYPE_POINTER:
348,695✔
2344
      case VCODE_TYPE_ACCESS:
2345
         return vtype_eq(at->pointed, bt->pointed);
348,695✔
2346
      case VCODE_TYPE_OFFSET:
2347
      case VCODE_TYPE_OPAQUE:
2348
      case VCODE_TYPE_DEBUG_LOCUS:
2349
      case VCODE_TYPE_TRIGGER:
2350
         return true;
2351
      case VCODE_TYPE_RESOLUTION:
64,344✔
2352
      case VCODE_TYPE_CLOSURE:
2353
      case VCODE_TYPE_SIGNAL:
2354
      case VCODE_TYPE_FILE:
2355
         return vtype_eq(at->base, bt->base);
64,344✔
2356
      case VCODE_TYPE_RECORD:
56,599✔
2357
      case VCODE_TYPE_CONTEXT:
2358
         return at->name == bt->name;
56,599✔
2359
      }
2360

2361
      return false;
×
2362
   }
2363
}
2364

2365
void vcode_dump(void)
×
2366
{
2367
   vcode_dump_with_mark(-1, NULL, NULL);
×
2368
}
×
2369

2370
static vcode_type_t vtype_new(vtype_t *new)
2371
{
2372
   int index = active_unit->types.count - 1;
2373
   vcode_type_t type = MAKE_HANDLE(active_unit->depth, index);
2374

2375
   for (int i = 0; i < index; i++) {
2376
      vcode_type_t this = MAKE_HANDLE(active_unit->depth, i);
2377
      if (vtype_eq(this, type)) {
2378
         active_unit->types.count--;
2379
         return this;
2380
      }
2381
   }
2382

2383
   return type;
2384
}
2385

2386
vcode_type_t vtype_int(int64_t low, int64_t high)
1,493,020✔
2387
{
2388
   assert(active_unit != NULL);
1,493,020✔
2389

2390
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,493,020✔
2391
   n->kind = VCODE_TYPE_INT;
1,493,020✔
2392
   n->low  = low;
1,493,020✔
2393
   n->high = high;
1,493,020✔
2394

2395
   switch (bits_for_range(low, high)) {
1,493,020✔
2396
   case 64:
115,842✔
2397
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
115,842✔
2398
      break;
115,842✔
2399
   case 32:
344,609✔
2400
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
344,609✔
2401
      break;
344,609✔
2402
   case 16:
2,571✔
2403
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
2,571✔
2404
      break;
2,571✔
2405
   case 8:
427,993✔
2406
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
427,993✔
2407
      break;
427,993✔
2408
   case 1:
602,004✔
2409
      n->repr = VCODE_REPR_U1;
602,004✔
2410
      break;
602,004✔
2411
   default:
×
2412
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
×
2413
   }
2414

2415
   return vtype_new(n);
1,493,020✔
2416
}
2417

2418
vcode_type_t vtype_bool(void)
301,875✔
2419
{
2420
   return vtype_int(0, 1);
301,875✔
2421
}
2422

2423
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
35,762✔
2424
{
2425
   assert(active_unit != NULL);
35,762✔
2426

2427
   const vtype_kind_t ekind = vtype_kind(elem);
35,762✔
2428
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
35,762✔
2429
                "array types may not be nested");
2430

2431
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
35,762✔
2432
   memset(n, '\0', sizeof(vtype_t));
35,762✔
2433
   n->kind   = VCODE_TYPE_CARRAY;
35,762✔
2434
   n->elem   = elem;
35,762✔
2435
   n->bounds = bounds;
35,762✔
2436
   n->size   = MAX(size, 0);
35,762✔
2437

2438
   return vtype_new(n);
35,762✔
2439
}
2440

2441
vcode_type_t vtype_find_named_record(ident_t name)
24,635✔
2442
{
2443
   assert(active_unit != NULL);
24,635✔
2444

2445
   for (int i = 0; i < active_unit->types.count; i++) {
343,132✔
2446
      vtype_t *other = &(active_unit->types.items[i]);
334,696✔
2447
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
334,696✔
2448
         return MAKE_HANDLE(active_unit->depth, i);
16,199✔
2449
   }
2450

2451
   return VCODE_INVALID_TYPE;
2452
}
2453

2454
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
8,436✔
2455
                                int nfields)
2456
{
2457
   assert(active_unit != NULL);
8,436✔
2458

2459
   vtype_t *data = NULL;
8,436✔
2460
   vcode_type_t handle = vtype_find_named_record(name);
8,436✔
2461
   if (handle == VCODE_INVALID_TYPE) {
8,436✔
2462
      data = vtype_array_alloc(&(active_unit->types));
4,226✔
2463
      memset(data, '\0', sizeof(vtype_t));
4,226✔
2464
      data->kind = VCODE_TYPE_RECORD;
4,226✔
2465
      data->name = name;
4,226✔
2466

2467
      handle = vtype_new(data);
4,226✔
2468
   }
2469
   else {
2470
      data = vcode_type_data(handle);
4,210✔
2471
      VCODE_ASSERT(data->fields.count == 0,
4,210✔
2472
                    "record type %s already defined", istr(name));
2473
   }
2474

2475
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
8,436✔
2476
   for (int i = 0; i < nfields; i++)
23,500✔
2477
      vcode_type_array_add(&(data->fields), field_types[i]);
15,064✔
2478

2479
   return handle;
8,436✔
2480
}
2481

2482
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
71,972✔
2483
{
2484
   assert(active_unit != NULL);
71,972✔
2485

2486
   const vtype_kind_t ekind = vtype_kind(elem);
71,972✔
2487
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
71,972✔
2488
                "array types may not be nested");
2489

2490
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
71,972✔
2491

2492
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
71,972✔
2493
   memset(n, '\0', sizeof(vtype_t));
71,972✔
2494
   n->kind   = VCODE_TYPE_UARRAY;
71,972✔
2495
   n->elem   = elem;
71,972✔
2496
   n->bounds = bounds;
71,972✔
2497
   n->dims   = ndim;
71,972✔
2498

2499
   return vtype_new(n);
71,972✔
2500
}
2501

2502
vcode_type_t vtype_pointer(vcode_type_t to)
146,128✔
2503
{
2504
   assert(active_unit != NULL);
146,128✔
2505

2506
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
146,128✔
2507
   n->kind    = VCODE_TYPE_POINTER;
146,128✔
2508
   n->pointed = to;
146,128✔
2509

2510
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
146,128✔
2511
                "cannot get pointer to carray type");
2512

2513
   return vtype_new(n);
146,128✔
2514
}
2515

2516
vcode_type_t vtype_access(vcode_type_t to)
4,386✔
2517
{
2518
   assert(active_unit != NULL);
4,386✔
2519

2520
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
4,386✔
2521
   n->kind    = VCODE_TYPE_ACCESS;
4,386✔
2522
   n->pointed = to;
4,386✔
2523

2524
   return vtype_new(n);
4,386✔
2525
}
2526

2527
vcode_type_t vtype_signal(vcode_type_t base)
25,293✔
2528
{
2529
   assert(active_unit != NULL);
25,293✔
2530

2531
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
25,293✔
2532
   n->kind = VCODE_TYPE_SIGNAL;
25,293✔
2533
   n->base = base;
25,293✔
2534

2535
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
25,293✔
2536

2537
   return vtype_new(n);
25,293✔
2538
}
2539

2540
vcode_type_t vtype_resolution(vcode_type_t base)
572✔
2541
{
2542
   assert(active_unit != NULL);
572✔
2543

2544
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
572✔
2545
   n->kind = VCODE_TYPE_RESOLUTION;
572✔
2546
   n->base = base;
572✔
2547

2548
   return vtype_new(n);
572✔
2549
}
2550

2551
vcode_type_t vtype_closure(vcode_type_t result)
710✔
2552
{
2553
   assert(active_unit != NULL);
710✔
2554

2555
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
710✔
2556
   n->kind = VCODE_TYPE_CLOSURE;
710✔
2557
   n->base = result;
710✔
2558

2559
   return vtype_new(n);
710✔
2560
}
2561

2562
vcode_type_t vtype_context(ident_t name)
44,574✔
2563
{
2564
   assert(active_unit != NULL);
44,574✔
2565
   assert(name != NULL);
44,574✔
2566

2567
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
44,574✔
2568
   n->kind = VCODE_TYPE_CONTEXT;
44,574✔
2569
   n->name = name;
44,574✔
2570

2571
   return vtype_new(n);
44,574✔
2572
}
2573

2574
vcode_type_t vtype_file(vcode_type_t base)
337✔
2575
{
2576
   assert(active_unit != NULL);
337✔
2577

2578
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
337✔
2579
   n->kind = VCODE_TYPE_FILE;
337✔
2580
   n->base = base;
337✔
2581

2582
   return vtype_new(n);
337✔
2583
}
2584

2585
vcode_type_t vtype_offset(void)
222,951✔
2586
{
2587
   assert(active_unit != NULL);
222,951✔
2588

2589
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
222,951✔
2590
   n->kind = VCODE_TYPE_OFFSET;
222,951✔
2591
   n->low  = INT64_MIN;
222,951✔
2592
   n->high = INT64_MAX;
222,951✔
2593
   n->repr = VCODE_REPR_I64;
222,951✔
2594

2595
   return vtype_new(n);
222,951✔
2596
}
2597

2598
vcode_type_t vtype_time(void)
13,985✔
2599
{
2600
   return vtype_int(INT64_MIN, INT64_MAX);
13,985✔
2601
}
2602

2603
vcode_type_t vtype_char(void)
8,564✔
2604
{
2605
   return vtype_int(0, 255);
8,564✔
2606
}
2607

2608
vcode_type_t vtype_opaque(void)
295✔
2609
{
2610
   assert(active_unit != NULL);
295✔
2611

2612
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
295✔
2613
   n->kind = VCODE_TYPE_OPAQUE;
295✔
2614

2615
   return vtype_new(n);
295✔
2616
}
2617

2618
vcode_type_t vtype_debug_locus(void)
84,718✔
2619
{
2620
   assert(active_unit != NULL);
84,718✔
2621

2622
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
84,718✔
2623
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
84,718✔
2624

2625
   return vtype_new(n);
84,718✔
2626
}
2627

2628
vcode_type_t vtype_trigger(void)
36✔
2629
{
2630
   assert(active_unit != NULL);
36✔
2631

2632
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
36✔
2633
   n->kind = VCODE_TYPE_TRIGGER;
36✔
2634

2635
   return vtype_new(n);
36✔
2636
}
2637

2638
vcode_type_t vtype_real(double low, double high)
75,155✔
2639
{
2640
   assert(active_unit != NULL);
75,155✔
2641

2642
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
75,155✔
2643
   n->kind  = VCODE_TYPE_REAL;
75,155✔
2644
   n->rlow  = low;
75,155✔
2645
   n->rhigh = high;
75,155✔
2646

2647
   return vtype_new(n);
75,155✔
2648
}
2649

2650
vtype_kind_t vtype_kind(vcode_type_t type)
5,137,530✔
2651
{
2652
   vtype_t *vt = vcode_type_data(type);
5,137,530✔
2653
   return vt->kind;
5,137,530✔
2654
}
2655

2656
vtype_repr_t vtype_repr(vcode_type_t type)
414,783✔
2657
{
2658
   vtype_t *vt = vcode_type_data(type);
414,783✔
2659
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
414,783✔
2660
   return vt->repr;
414,783✔
2661
}
2662

2663
vcode_type_t vtype_elem(vcode_type_t type)
321,048✔
2664
{
2665
   vtype_t *vt = vcode_type_data(type);
321,048✔
2666
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
321,048✔
2667
   return vt->elem;
321,048✔
2668
}
2669

2670
vcode_type_t vtype_base(vcode_type_t type)
11,434✔
2671
{
2672
   vtype_t *vt = vcode_type_data(type);
11,434✔
2673
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
11,434✔
2674
          || vt->kind == VCODE_TYPE_RESOLUTION
2675
          || vt->kind == VCODE_TYPE_CLOSURE);
2676
   return vt->base;
11,434✔
2677
}
2678

2679
vcode_type_t vtype_bounds(vcode_type_t type)
11,151✔
2680
{
2681
   vtype_t *vt = vcode_type_data(type);
11,151✔
2682
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
11,151✔
2683
   return vt->bounds;
11,151✔
2684
}
2685

2686
unsigned vtype_dims(vcode_type_t type)
115,223✔
2687
{
2688
   vtype_t *vt = vcode_type_data(type);
115,223✔
2689
   assert(vt->kind == VCODE_TYPE_UARRAY);
115,223✔
2690
   return vt->dims;
115,223✔
2691
}
2692

2693
unsigned vtype_size(vcode_type_t type)
75,795✔
2694
{
2695
   vtype_t *vt = vcode_type_data(type);
75,795✔
2696
   assert(vt->kind == VCODE_TYPE_CARRAY);
75,795✔
2697
   return vt->size;
75,795✔
2698
}
2699

2700
int vtype_fields(vcode_type_t type)
17,636✔
2701
{
2702
   vtype_t *vt = vcode_type_data(type);
17,636✔
2703
   assert(vt->kind == VCODE_TYPE_RECORD);
17,636✔
2704
   return vt->fields.count;
17,636✔
2705
}
2706

2707
vcode_type_t vtype_field(vcode_type_t type, int field)
165,390✔
2708
{
2709
   vtype_t *vt = vcode_type_data(type);
165,390✔
2710
   assert(vt->kind == VCODE_TYPE_RECORD);
165,390✔
2711
   return vcode_type_array_nth(&(vt->fields), field);
165,390✔
2712
}
2713

2714
ident_t vtype_name(vcode_type_t type)
2,643✔
2715
{
2716
   vtype_t *vt = vcode_type_data(type);
2,643✔
2717
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
2,643✔
2718
   return vt->name;
2,643✔
2719
}
2720

2721
vcode_type_t vtype_pointed(vcode_type_t type)
280,100✔
2722
{
2723
   vtype_t *vt = vcode_type_data(type);
280,100✔
2724
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
280,100✔
2725
   return vt->pointed;
280,100✔
2726
}
2727

2728
int64_t vtype_low(vcode_type_t type)
98✔
2729
{
2730
   vtype_t *vt = vcode_type_data(type);
98✔
2731
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
98✔
2732
   return vt->low;
98✔
2733
}
2734

2735
int64_t vtype_high(vcode_type_t type)
545✔
2736
{
2737
   vtype_t *vt = vcode_type_data(type);
545✔
2738
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
545✔
2739
   return vt->high;
545✔
2740
}
2741

2742
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
522✔
2743
{
2744
   return vtype_kind(type) == VCODE_TYPE_POINTER
522✔
2745
      && vtype_kind(vtype_pointed(type)) == to;
522✔
2746
}
2747

2748
bool vtype_is_scalar(vcode_type_t type)
286,454✔
2749
{
2750
   const vtype_kind_t kind = vtype_kind(type);
286,454✔
2751
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
286,454✔
2752
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
81,572✔
2753
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
60,714✔
2754
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
57,712✔
2755
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER;
287,893✔
2756
}
2757

2758
bool vtype_is_composite(vcode_type_t type)
23,727✔
2759
{
2760
   const vtype_kind_t kind = vtype_kind(type);
23,727✔
2761
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
23,727✔
2762
}
2763

2764
bool vtype_is_signal(vcode_type_t type)
145,320✔
2765
{
2766
   vtype_t *vt = vcode_type_data(type);
260,702✔
2767
   switch (vt->kind) {
260,702✔
2768
   case VCODE_TYPE_SIGNAL:
2769
      return true;
2770
   case VCODE_TYPE_POINTER:
61,173✔
2771
      return vtype_is_signal(vt->pointed);
61,173✔
2772
   case VCODE_TYPE_RECORD:
2773
      for (int i = 0; i < vt->fields.count; i++) {
29,013✔
2774
         if (vtype_is_signal(vt->fields.items[i]))
23,328✔
2775
            return true;
2776
      }
2777
      return false;
2778
   case VCODE_TYPE_UARRAY:
54,209✔
2779
   case VCODE_TYPE_CARRAY:
2780
      return vtype_is_signal(vt->elem);
54,209✔
2781
   default:
122,996✔
2782
      return false;
122,996✔
2783
   }
2784
}
2785

2786
int vtype_repr_bits(vtype_repr_t repr)
331,057✔
2787
{
2788
   switch (repr) {
331,057✔
2789
   case VCODE_REPR_U1: return 1;
2790
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2791
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2792
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2793
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2794
   default: return -1;
2795
   }
2796
}
2797

2798
bool vtype_repr_signed(vtype_repr_t repr)
41,829✔
2799
{
2800
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
41,829✔
2801
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
41,829✔
2802
}
2803

2804
static int64_t vtype_repr_low(vtype_repr_t repr)
7,879✔
2805
{
2806
   switch (repr) {
7,879✔
2807
   case VCODE_REPR_U1:
2808
   case VCODE_REPR_U8:
2809
   case VCODE_REPR_U16:
2810
   case VCODE_REPR_U32:
2811
   case VCODE_REPR_U64: return 0;
2812
   case VCODE_REPR_I8:  return INT8_MIN;
2813
   case VCODE_REPR_I16: return INT16_MIN;
2814
   case VCODE_REPR_I32: return INT32_MIN;
2815
   case VCODE_REPR_I64: return INT64_MIN;
2816
   default:             return 0;
2817
   }
2818
}
2819

2820
static uint64_t vtype_repr_high(vtype_repr_t repr)
7,879✔
2821
{
2822
   switch (repr) {
7,879✔
2823
   case VCODE_REPR_U1:  return 1;
2824
   case VCODE_REPR_U8:  return UINT8_MAX;
2825
   case VCODE_REPR_U16: return UINT16_MAX;
2826
   case VCODE_REPR_U32: return UINT32_MAX;
2827
   case VCODE_REPR_U64: return UINT64_MAX;
2828
   case VCODE_REPR_I8:  return INT8_MAX;
2829
   case VCODE_REPR_I16: return INT16_MAX;
2830
   case VCODE_REPR_I32: return INT32_MAX;
2831
   case VCODE_REPR_I64: return INT64_MAX;
2832
   default:             return 0;
2833
   }
2834
}
2835

2836
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
7,879✔
2837
{
2838
   int64_t clamp_low = vtype_repr_low(repr);
7,879✔
2839
   uint64_t clamp_high = vtype_repr_high(repr);
7,879✔
2840

2841
   if (*low >= clamp_low && *high <= clamp_high)
7,879✔
2842
      return true;
2843
   else {
2844
      *low = MAX(clamp_low, *low);
4,454✔
2845
      *high = MIN(clamp_high, *high);
4,454✔
2846
      return false;
4,454✔
2847
   }
2848
}
2849

2850
int vcode_count_params(void)
9,759✔
2851
{
2852
   assert(active_unit != NULL);
9,759✔
2853
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
9,759✔
2854
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2855
          || active_unit->kind == VCODE_UNIT_PROPERTY
2856
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2857

2858
   return active_unit->params.count;
9,759✔
2859
}
2860

2861
vcode_type_t vcode_param_type(int param)
25,938✔
2862
{
2863
   assert(active_unit != NULL);
25,938✔
2864
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
25,938✔
2865
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2866
          || active_unit->kind == VCODE_UNIT_PROPERTY
2867
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2868
   assert(param < active_unit->params.count);
25,938✔
2869

2870
   return active_unit->params.items[param].type;
25,938✔
2871
}
2872

2873
vcode_reg_t vcode_param_reg(int param)
33,088✔
2874
{
2875
   assert(active_unit != NULL);
33,088✔
2876
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
33,088✔
2877
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2878
          || active_unit->kind == VCODE_UNIT_PROPERTY
2879
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2880
   assert(param < active_unit->params.count);
33,088✔
2881

2882
   return active_unit->params.items[param].reg;
33,088✔
2883
}
2884

2885
vcode_block_t emit_block(void)
117,328✔
2886
{
2887
   assert(active_unit != NULL);
117,328✔
2888

2889
   vcode_block_t bnum = active_unit->blocks.count;
117,328✔
2890

2891
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
117,328✔
2892
   memset(bptr, '\0', sizeof(block_t));
117,328✔
2893

2894
   if (active_block != VCODE_INVALID_BLOCK)
117,328✔
2895
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
81,621✔
2896
   else
2897
      bptr->last_loc = LOC_INVALID;
35,707✔
2898

2899
   return bnum;
117,328✔
2900
}
2901

2902
void vcode_select_unit(vcode_unit_t unit)
316,821✔
2903
{
2904
   active_unit  = unit;
316,821✔
2905
   active_block = VCODE_INVALID_BLOCK;
316,821✔
2906
}
316,821✔
2907

2908
void vcode_select_block(vcode_block_t block)
524,092✔
2909
{
2910
   assert(active_unit != NULL);
524,092✔
2911
   active_block = block;
524,092✔
2912
}
524,092✔
2913

2914
vcode_block_t vcode_active_block(void)
1,261,170✔
2915
{
2916
   assert(active_unit != NULL);
1,261,170✔
2917
   assert(active_block != -1);
1,261,170✔
2918
   return active_block;
1,261,170✔
2919
}
2920

2921
const loc_t *vcode_last_loc(void)
715,189✔
2922
{
2923
   return &(vcode_block_data()->last_loc);
715,189✔
2924
}
2925

2926
vcode_unit_t vcode_active_unit(void)
40,959✔
2927
{
2928
   assert(active_unit != NULL);
40,959✔
2929
   return active_unit;
40,959✔
2930
}
2931

2932
ident_t vcode_unit_name(void)
236,755✔
2933
{
2934
   assert(active_unit != NULL);
236,755✔
2935
   return active_unit->name;
236,755✔
2936
}
2937

2938
bool vcode_unit_has_undefined(void)
9,729✔
2939
{
2940
   assert(active_unit != NULL);
9,729✔
2941
   return !!(active_unit->flags & UNIT_UNDEFINED);
9,729✔
2942
}
2943

2944
bool vcode_unit_has_escaping_tlab(vcode_unit_t vu)
4,476✔
2945
{
2946
   return !!(vu->flags & UNIT_ESCAPING_TLAB);
4,476✔
2947
}
2948

2949
int vcode_unit_depth(void)
×
2950
{
2951
   assert(active_unit != NULL);
×
2952
   return active_unit->depth;
×
2953
}
2954

2955
void vcode_set_result(vcode_type_t type)
18,236✔
2956
{
2957
   assert(active_unit != NULL);
18,236✔
2958
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
18,236✔
2959
          || active_unit->kind == VCODE_UNIT_THUNK);
2960

2961
   active_unit->result = type;
18,236✔
2962
}
18,236✔
2963

2964
vcode_type_t vcode_unit_result(void)
26,907✔
2965
{
2966
   assert(active_unit != NULL);
26,907✔
2967
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
26,907✔
2968
          || active_unit->kind == VCODE_UNIT_THUNK);
2969
   return active_unit->result;
26,907✔
2970
}
2971

2972
vunit_kind_t vcode_unit_kind(void)
324,028✔
2973
{
2974
   assert(active_unit != NULL);
324,028✔
2975
   return active_unit->kind;
324,028✔
2976
}
2977

2978
vcode_unit_t vcode_unit_context(void)
99,158✔
2979
{
2980
   assert(active_unit != NULL);
99,158✔
2981
   return active_unit->context;
99,158✔
2982
}
2983

2984
void vcode_unit_object(vcode_unit_t vu, ident_t *module, ptrdiff_t *offset)
42,457✔
2985
{
2986
   assert(vu != NULL);
42,457✔
2987
   *module = vu->module;
42,457✔
2988
   *offset = vu->offset;
42,457✔
2989
}
42,457✔
2990

2991
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
45,445✔
2992
{
2993
   int hops = 0;
45,445✔
2994
   for (; (unit = unit->context); hops++)
92,368✔
2995
      ;
46,923✔
2996
   return hops;
45,445✔
2997
}
2998

2999
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
3000
{
3001
   assert(context->kind != VCODE_UNIT_THUNK);
3002

3003
   child->next = NULL;
3004
   if (context->children == NULL)
3005
      context->children = child;
3006
   else {
3007
      vcode_unit_t it;
3008
      for (it = context->children; it->next != NULL; it = it->next)
3009
         ;
3010
      it->next = child;
3011
   }
3012
}
3013

3014
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
9,551✔
3015
{
3016
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,551✔
3017
   vu->kind     = VCODE_UNIT_FUNCTION;
9,551✔
3018
   vu->name     = name;
9,551✔
3019
   vu->context  = context;
9,551✔
3020
   vu->result   = VCODE_INVALID_TYPE;
9,551✔
3021
   vu->depth    = vcode_unit_calc_depth(vu);
9,551✔
3022

3023
   object_locus(obj, &vu->module, &vu->offset);
9,551✔
3024

3025
   vcode_add_child(context, vu);
9,551✔
3026

3027
   vcode_select_unit(vu);
9,551✔
3028
   vcode_select_block(emit_block());
9,551✔
3029
   emit_debug_info(&(obj->loc));
9,551✔
3030

3031
   return vu;
9,551✔
3032
}
3033

3034
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
407✔
3035
{
3036
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
407✔
3037
   vu->kind     = VCODE_UNIT_PROCEDURE;
407✔
3038
   vu->name     = name;
407✔
3039
   vu->context  = context;
407✔
3040
   vu->result   = VCODE_INVALID_TYPE;
407✔
3041
   vu->depth    = vcode_unit_calc_depth(vu);
407✔
3042

3043
   object_locus(obj, &vu->module, &vu->offset);
407✔
3044

3045
   vcode_add_child(context, vu);
407✔
3046

3047
   vcode_select_unit(vu);
407✔
3048
   vcode_select_block(emit_block());
407✔
3049
   emit_debug_info(&(obj->loc));
407✔
3050

3051
   return vu;
407✔
3052
}
3053

3054
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
7,450✔
3055
{
3056
   assert(context->kind == VCODE_UNIT_INSTANCE);
7,450✔
3057

3058
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
7,450✔
3059
   vu->kind     = VCODE_UNIT_PROCESS;
7,450✔
3060
   vu->name     = name;
7,450✔
3061
   vu->context  = context;
7,450✔
3062
   vu->depth    = vcode_unit_calc_depth(vu);
7,450✔
3063
   vu->result   = VCODE_INVALID_TYPE;
7,450✔
3064

3065
   object_locus(obj, &vu->module, &vu->offset);
7,450✔
3066

3067
   vcode_add_child(context, vu);
7,450✔
3068

3069
   vcode_select_unit(vu);
7,450✔
3070
   vcode_select_block(emit_block());
7,450✔
3071
   emit_debug_info(&(obj->loc));
7,450✔
3072

3073
   return vu;
7,450✔
3074
}
3075

3076
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
6,908✔
3077
{
3078
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
6,908✔
3079

3080
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
6,908✔
3081
   vu->kind     = VCODE_UNIT_INSTANCE;
6,908✔
3082
   vu->name     = name;
6,908✔
3083
   vu->context  = context;
6,908✔
3084
   vu->depth    = vcode_unit_calc_depth(vu);
6,908✔
3085
   vu->result   = VCODE_INVALID_TYPE;
6,908✔
3086

3087
   object_locus(obj, &vu->module, &vu->offset);
6,908✔
3088

3089
   if (context != NULL)
6,908✔
3090
      vcode_add_child(context, vu);
3,997✔
3091

3092
   vcode_select_unit(vu);
6,908✔
3093
   vcode_select_block(emit_block());
6,908✔
3094
   emit_debug_info(&(obj->loc));
6,908✔
3095

3096
   return vu;
6,908✔
3097
}
3098

3099
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
1,417✔
3100
{
3101
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
1,417✔
3102
   vu->kind     = VCODE_UNIT_PACKAGE;
1,417✔
3103
   vu->name     = name;
1,417✔
3104
   vu->context  = context;
1,417✔
3105
   vu->depth    = vcode_unit_calc_depth(vu);
1,417✔
3106
   vu->result   = VCODE_INVALID_TYPE;
1,417✔
3107

3108
   object_locus(obj, &vu->module, &vu->offset);
1,417✔
3109

3110
   if (context != NULL)
1,417✔
3111
      vcode_add_child(context, vu);
130✔
3112

3113
   vcode_select_unit(vu);
1,417✔
3114
   vcode_select_block(emit_block());
1,417✔
3115
   emit_debug_info(&(obj->loc));
1,417✔
3116

3117
   return vu;
1,417✔
3118
}
3119

3120
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
155✔
3121
{
3122
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
155✔
3123
   vu->kind     = VCODE_UNIT_PROTECTED;
155✔
3124
   vu->name     = name;
155✔
3125
   vu->context  = context;
155✔
3126
   vu->depth    = vcode_unit_calc_depth(vu);
155✔
3127
   vu->result   = VCODE_INVALID_TYPE;
155✔
3128

3129
   object_locus(obj, &vu->module, &vu->offset);
155✔
3130

3131
   if (context != NULL)
155✔
3132
      vcode_add_child(context, vu);
155✔
3133

3134
   vcode_select_unit(vu);
155✔
3135
   vcode_select_block(emit_block());
155✔
3136
   emit_debug_info(&(obj->loc));
155✔
3137

3138
   return vu;
155✔
3139
}
3140

3141
vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context)
81✔
3142
{
3143
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
81✔
3144
   vu->kind     = VCODE_UNIT_PROPERTY;
81✔
3145
   vu->name     = name;
81✔
3146
   vu->context  = context;
81✔
3147
   vu->depth    = vcode_unit_calc_depth(vu);
81✔
3148
   vu->result   = VCODE_INVALID_TYPE;
81✔
3149

3150
   object_locus(obj, &vu->module, &vu->offset);
81✔
3151

3152
   if (context != NULL)
81✔
3153
      vcode_add_child(context, vu);
81✔
3154

3155
   vcode_select_unit(vu);
81✔
3156
   vcode_select_block(emit_block());
81✔
3157
   emit_debug_info(&(obj->loc));
81✔
3158

3159
   return vu;
81✔
3160
}
3161

3162
vcode_unit_t emit_thunk(ident_t name, object_t *obj, vcode_unit_t context)
9,738✔
3163
{
3164
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,738✔
3165
   vu->kind     = VCODE_UNIT_THUNK;
9,738✔
3166
   vu->name     = name;
9,738✔
3167
   vu->context  = context;
9,738✔
3168
   vu->depth    = vcode_unit_calc_depth(vu);
9,738✔
3169
   vu->result   = VCODE_INVALID_TYPE;
9,738✔
3170
   vu->depth    = vcode_unit_calc_depth(vu);
9,738✔
3171

3172
   object_locus(obj, &vu->module, &vu->offset);
9,738✔
3173

3174
   if (context != NULL)
9,738✔
3175
      vcode_add_child(context, vu);
125✔
3176

3177
   vcode_select_unit(vu);
9,738✔
3178
   vcode_select_block(emit_block());
9,738✔
3179

3180
   return vu;
9,738✔
3181
}
3182

3183
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
12,888✔
3184
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3185
                 vcode_reg_t hint_right)
3186
{
3187
   int64_t value_const;
12,888✔
3188
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
12,888✔
3189
      emit_comment("Always true assertion on r%d", value);
×
3190
      return;
×
3191
   }
3192

3193
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
12,888✔
3194
   vcode_add_arg(op, value);
12,888✔
3195
   vcode_add_arg(op, severity);
12,888✔
3196
   vcode_add_arg(op, message);
12,888✔
3197
   vcode_add_arg(op, length);
12,888✔
3198
   vcode_add_arg(op, locus);
12,888✔
3199

3200
   if (hint_left != VCODE_INVALID_REG) {
12,888✔
3201
      vcode_add_arg(op, hint_left);
5,054✔
3202
      vcode_add_arg(op, hint_right);
5,054✔
3203

3204
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
5,054✔
3205
                   "left hint must be scalar");
3206
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
5,054✔
3207
                   "right hint must be scalar");
3208
   }
3209

3210
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
12,888✔
3211
                "value parameter to assert is not bool");
3212
   VCODE_ASSERT(message == VCODE_INVALID_REG
12,888✔
3213
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3214
                "message parameter to assert is not a pointer");
3215
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
12,888✔
3216
                "value parameter to assert is not bool");
3217
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
12,888✔
3218
                "locus argument to report must be a debug locus");
3219
}
3220

3221
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,081✔
3222
                 vcode_reg_t locus)
3223
{
3224
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,081✔
3225
   vcode_add_arg(op, severity);
2,081✔
3226
   vcode_add_arg(op, message);
2,081✔
3227
   vcode_add_arg(op, length);
2,081✔
3228
   vcode_add_arg(op, locus);
2,081✔
3229

3230
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,081✔
3231
                "message parameter to report is not a pointer");
3232
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,081✔
3233
                "message parameter to report is not a character pointer");
3234
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,081✔
3235
                "locus argument to report must be a debug locus");
3236
}
2,081✔
3237

3238
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
33,872✔
3239
{
3240
   if (lhs == rhs) {
33,872✔
3241
      if (cmp == VCODE_CMP_EQ)
939✔
3242
         return emit_const(vtype_bool(), 1);
932✔
3243
      else if (cmp == VCODE_CMP_NEQ)
7✔
3244
         return emit_const(vtype_bool(), 0);
×
3245
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
7✔
3246
         return emit_const(vtype_bool(), 1);
×
3247
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
7✔
3248
         return emit_const(vtype_bool(), 0);
7✔
3249
   }
3250

3251
   int64_t lconst, rconst;
32,933✔
3252
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
32,933✔
3253
      switch (cmp) {
244✔
3254
      case VCODE_CMP_EQ:
243✔
3255
         return emit_const(vtype_bool(), lconst == rconst);
243✔
3256
      case VCODE_CMP_NEQ:
×
3257
         return emit_const(vtype_bool(), lconst != rconst);
×
3258
      case VCODE_CMP_LT:
×
3259
         return emit_const(vtype_bool(), lconst < rconst);
×
3260
      case VCODE_CMP_GT:
1✔
3261
         return emit_const(vtype_bool(), lconst > rconst);
1✔
3262
      case VCODE_CMP_LEQ:
×
3263
         return emit_const(vtype_bool(), lconst <= rconst);
×
3264
      case VCODE_CMP_GEQ:
×
3265
         return emit_const(vtype_bool(), lconst >= rconst);
×
3266
      default:
×
3267
         fatal_trace("cannot fold comparison %d", cmp);
×
3268
      }
3269
   }
3270

3271
   // Reuse any previous operation in this block with the same arguments
3272
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
588,034✔
3273
      if (other->args.count == 2 && other->args.items[0] == lhs
26,168✔
3274
          && other->args.items[1] == rhs && other->cmp == cmp)
1,421✔
3275
         return other->result;
355✔
3276
   }
3277

3278
   op_t *op = vcode_add_op(VCODE_OP_CMP);
32,334✔
3279
   vcode_add_arg(op, lhs);
32,334✔
3280
   vcode_add_arg(op, rhs);
32,334✔
3281
   op->cmp    = cmp;
32,334✔
3282
   op->result = vcode_add_reg(vtype_bool());
32,334✔
3283

3284
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
32,334✔
3285
                "arguments to cmp are not the same type");
3286

3287
   return op->result;
3288
}
3289

3290
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_type_t bounds,
31,574✔
3291
                       vcode_cc_t cc, const vcode_reg_t *args, int nargs)
3292
{
3293
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
31,574✔
3294
   o->func    = func;
31,574✔
3295
   o->type    = type;
31,574✔
3296
   o->subkind = cc;
31,574✔
3297
   for (int i = 0; i < nargs; i++)
120,635✔
3298
      vcode_add_arg(o, args[i]);
89,061✔
3299

3300
   for (int i = 0; i < nargs; i++)
120,635✔
3301
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
89,061✔
3302
                   "invalid argument to function");
3303

3304
   if (cc != VCODE_CC_FOREIGN && cc != VCODE_CC_VARIADIC)
31,574✔
3305
      VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
30,760✔
3306
                   "first argument to VHDL function must be context pointer");
3307

3308
   if (type == VCODE_INVALID_TYPE)
31,574✔
3309
      return (o->result = VCODE_INVALID_REG);
3,315✔
3310
   else {
3311
      o->result = vcode_add_reg(type);
28,259✔
3312

3313
      reg_t *rr = vcode_reg_data(o->result);
28,259✔
3314
      rr->bounds = bounds;
28,259✔
3315

3316
      return o->result;
28,259✔
3317
   }
3318
}
3319

3320
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
1,971✔
3321
                vcode_block_t resume_bb)
3322
{
3323
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
1,971✔
3324
   o->func    = func;
1,971✔
3325
   o->subkind = VCODE_CC_VHDL;
1,971✔
3326
   for (int i = 0; i < nargs; i++)
9,283✔
3327
      vcode_add_arg(o, args[i]);
7,312✔
3328

3329
   vcode_block_array_add(&(o->targets), resume_bb);
1,971✔
3330

3331
   for (int i = 0; i < nargs; i++)
9,283✔
3332
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
7,312✔
3333
                   "invalid argument to procedure");
3334

3335
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
1,971✔
3336
                "first argument to VHDL procedure must be context pointer");
3337
}
1,971✔
3338

3339
vcode_reg_t emit_alloc(vcode_type_t type, vcode_type_t bounds,
5,843✔
3340
                       vcode_reg_t count)
3341
{
3342
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
5,843✔
3343
   op->type    = type;
5,843✔
3344
   op->result  = vcode_add_reg(vtype_pointer(type));
5,843✔
3345
   vcode_add_arg(op, count);
5,843✔
3346

3347
   const vtype_kind_t tkind = vtype_kind(type);
5,843✔
3348
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
5,843✔
3349
                "alloca element type cannot be array");
3350
   VCODE_ASSERT(count != VCODE_INVALID_REG,
5,843✔
3351
                "alloca must have valid count argument");
3352

3353
   reg_t *r = vcode_reg_data(op->result);
5,843✔
3354
   r->bounds = bounds;
5,843✔
3355

3356
   return op->result;
5,843✔
3357
}
3358

3359
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
1,034,700✔
3360
{
3361
   // Reuse any previous constant in this block with the same type and value
3362
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
30,356,100✔
3363
      if (other->kind == VCODE_OP_CONST && other->value == value
8,650,220✔
3364
          && vtype_eq(type, other->type))
919,722✔
3365
         return other->result;
611,073✔
3366
   }
3367

3368
   op_t *op = vcode_add_op(VCODE_OP_CONST);
423,626✔
3369
   op->value  = value;
423,626✔
3370
   op->type   = type;
423,626✔
3371
   op->result = vcode_add_reg(type);
423,626✔
3372

3373
   vtype_kind_t type_kind = vtype_kind(type);
423,626✔
3374
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
423,626✔
3375
                "constant must have integer or offset type");
3376

3377
   reg_t *r = vcode_reg_data(op->result);
423,626✔
3378
   r->bounds = vtype_int(value, value);
423,626✔
3379

3380
   return op->result;
423,626✔
3381
}
3382

3383
vcode_reg_t emit_const_real(vcode_type_t type, double value)
33,175✔
3384
{
3385
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
1,185,780✔
3386
      if (other->real == value && other->type == type)
849,322✔
3387
         return other->result;
9,656✔
3388
   }
3389

3390
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
23,519✔
3391
   op->real   = value;
23,519✔
3392
   op->type   = type;
23,519✔
3393
   op->result = vcode_add_reg(op->type);
23,519✔
3394

3395
   reg_t *r = vcode_reg_data(op->result);
23,519✔
3396
   r->bounds = vtype_real(value, value);
23,519✔
3397

3398
   return op->result;
23,519✔
3399
}
3400

3401
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
27,488✔
3402
{
3403
   vtype_kind_t kind = vtype_kind(type);
27,488✔
3404

3405
   // Reuse any previous operation in this block with the same arguments
3406
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,071,900✔
3407
      if (other->args.count != num)
103,613✔
3408
         continue;
57,880✔
3409
      else if (!vtype_eq(vcode_reg_type(other->result), type))
45,733✔
3410
         continue;
463✔
3411

3412
      bool match = true;
3413
      for (int i = 0; match && i < num; i++) {
284,845✔
3414
         if (other->args.items[i] != values[i])
239,575✔
3415
            match = false;
40,085✔
3416
      }
3417

3418
      if (match) return other->result;
45,270✔
3419
   }
3420

3421
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
22,303✔
3422
   op->result = vcode_add_reg(type);
22,303✔
3423

3424
   for (int i = 0; i < num; i++)
1,187,280✔
3425
      vcode_add_arg(op, values[i]);
1,164,970✔
3426

3427
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
22,303✔
3428
                "constant array must have constrained array type");
3429
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
22,303✔
3430
                vtype_size(type), num);
3431

3432
#ifdef DEBUG
3433
   vcode_type_t elem = vtype_elem(type);
22,303✔
3434
   for (int i = 0; i < num; i++) {
1,187,280✔
3435
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,164,970✔
3436
                   "wrong element type for item %d", i);
3437
      vcode_assert_const(values[i], "array");
1,164,970✔
3438
   }
3439
#endif
3440

3441
   reg_t *r = vcode_reg_data(op->result);
22,303✔
3442
   r->bounds = vtype_elem(type);
22,303✔
3443

3444
   return op->result;
22,303✔
3445
}
3446

3447
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
935✔
3448
{
3449
   // Reuse any previous operation in this block with the same arguments
3450
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
18,129✔
3451
      if (other->args.items[0] == value && other->value == rep)
870✔
3452
         return other->result;
279✔
3453
   }
3454

3455
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
656✔
3456
   op->value = rep;
656✔
3457
   vcode_add_arg(op, value);
656✔
3458

3459
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
656✔
3460
                "constant array must have constrained array type");
3461

3462
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
656✔
3463

3464
   op->result = vcode_add_reg(type);
656✔
3465

3466
   reg_t *r = vcode_reg_data(op->result);
656✔
3467
   r->bounds = vtype_bounds(type);
656✔
3468

3469
   return op->result;
656✔
3470
}
3471

3472
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
1,981✔
3473
{
3474
   // Reuse any previous constant in this block with the same type and value
3475
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
47,618✔
3476
      if (vtype_eq(type, other->type) && other->args.count == num) {
1,439✔
3477
         bool same_regs = true;
3478
         for (int i = 0; i < num; i++)
2,964✔
3479
            same_regs = same_regs && other->args.items[i] == values[i];
3,525✔
3480

3481
         if (same_regs && vtype_eq(vcode_reg_type(other->result), type))
831✔
3482
            return other->result;
217✔
3483
      }
3484
   }
3485

3486
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
1,764✔
3487
   op->type   = type;
1,764✔
3488
   op->result = vcode_add_reg(type);
1,764✔
3489

3490
   for (int i = 0; i < num; i++)
7,045✔
3491
      vcode_add_arg(op, values[i]);
5,281✔
3492

3493
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
1,764✔
3494
                "constant record must have record type");
3495

3496
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
1,764✔
3497
                vtype_fields(type), num);
3498

3499
#ifdef DEBUG
3500
   for (int i = 0; i < num; i++) {
7,045✔
3501
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
5,281✔
3502
                   "wrong type for field %d", i);
3503
      vcode_assert_const(values[i], "record");
5,281✔
3504
   }
3505
#endif
3506

3507
   return op->result;
1,764✔
3508
}
3509

3510
vcode_reg_t emit_address_of(vcode_reg_t value)
28,946✔
3511
{
3512
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
1,145,200✔
3513
      if (other->args.items[0] == value)
105,030✔
3514
         return other->result;
5,219✔
3515
   }
3516

3517
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
23,727✔
3518
   vcode_add_arg(op, value);
23,727✔
3519

3520
   vcode_type_t type = vcode_reg_type(value);
23,727✔
3521
   VCODE_ASSERT(vtype_is_composite(type),
23,727✔
3522
                "address of argument must be record or array");
3523

3524
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
23,727✔
3525
      vcode_type_t elem = vtype_elem(type);
22,432✔
3526
      op->result = vcode_add_reg(vtype_pointer(elem));
22,432✔
3527

3528
      reg_t *rr = vcode_reg_data(op->result);
22,432✔
3529
      rr->bounds = elem;
22,432✔
3530

3531
      return op->result;
22,432✔
3532
   }
3533
   else
3534
      return (op->result = vcode_add_reg(vtype_pointer(type)));
1,295✔
3535
}
3536

3537
void emit_wait(vcode_block_t target, vcode_reg_t time)
10,753✔
3538
{
3539
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
10,753✔
3540
   vcode_add_target(op, target);
10,753✔
3541
   vcode_add_arg(op, time);
10,753✔
3542

3543
   VCODE_ASSERT(time == VCODE_INVALID_REG
10,753✔
3544
                || vcode_reg_kind(time) == VCODE_TYPE_INT,
3545
                "wait time must have integer type");
3546
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
10,753✔
3547
                || active_unit->kind == VCODE_UNIT_PROCESS,
3548
                "wait only allowed in process or procedure");
3549
}
10,753✔
3550

3551
void emit_jump(vcode_block_t target)
31,740✔
3552
{
3553
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
31,740✔
3554
   vcode_add_target(op, target);
31,740✔
3555
}
31,740✔
3556

3557
vcode_var_t emit_var(vcode_type_t type, vcode_type_t bounds, ident_t name,
37,695✔
3558
                     vcode_var_flags_t flags)
3559
{
3560
   assert(active_unit != NULL);
37,695✔
3561

3562
   vcode_var_t var = active_unit->vars.count;
37,695✔
3563
   var_t *v = var_array_alloc(&(active_unit->vars));
37,695✔
3564
   memset(v, '\0', sizeof(var_t));
37,695✔
3565
   v->type     = type;
37,695✔
3566
   v->bounds   = bounds;
37,695✔
3567
   v->name     = name;
37,695✔
3568
   v->flags    = flags;
37,695✔
3569

3570
   return var;
37,695✔
3571
}
3572

3573
vcode_reg_t emit_param(vcode_type_t type, vcode_type_t bounds, ident_t name)
27,216✔
3574
{
3575
   assert(active_unit != NULL);
27,216✔
3576

3577
   param_t *p = param_array_alloc(&(active_unit->params));
27,216✔
3578
   memset(p, '\0', sizeof(param_t));
27,216✔
3579
   p->type   = type;
27,216✔
3580
   p->bounds = bounds;
27,216✔
3581
   p->name   = name;
27,216✔
3582
   p->reg    = vcode_add_reg(type);
27,216✔
3583

3584
   reg_t *rr = vcode_reg_data(p->reg);
27,216✔
3585
   rr->bounds = bounds;
27,216✔
3586

3587
   return p->reg;
27,216✔
3588
}
3589

3590
vcode_reg_t emit_load(vcode_var_t var)
45,793✔
3591
{
3592
   // Try scanning backwards through the block for another load or store to
3593
   // this variable
3594
   vcode_reg_t fold = VCODE_INVALID_REG;
45,793✔
3595
   bool aliased = false;
45,793✔
3596
   VCODE_FOR_EACH_OP(other) {
508,524✔
3597
      if (fold == VCODE_INVALID_REG) {
471,328✔
3598
         if (other->kind == VCODE_OP_LOAD && other->address == var)
261,483✔
3599
            fold = other->result;
2,860✔
3600
         else if (other->kind == VCODE_OP_STORE && other->address == var)
258,623✔
3601
            fold = other->args.items[0];
10,224✔
3602
      }
3603

3604
      if (other->kind == VCODE_OP_INDEX && other->address == var)
471,328✔
3605
         aliased = true;
3606
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
471,259✔
3607
         break;   // Nested call captures variables
3608
      else if (other->kind == VCODE_OP_FILE_READ)
462,719✔
3609
         break;   // May write to variable
3610
   }
3611

3612
   var_t *v = vcode_var_data(var);
45,793✔
3613

3614
   if (fold != VCODE_INVALID_REG && !aliased)
45,793✔
3615
      return fold;
3616

3617
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
32,742✔
3618
   op->address = var;
32,742✔
3619
   op->result  = vcode_add_reg(v->type);
32,742✔
3620

3621
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
32,742✔
3622

3623
   reg_t *r = vcode_reg_data(op->result);
32,742✔
3624
   r->bounds = v->bounds;
32,742✔
3625

3626
   return op->result;
32,742✔
3627
}
3628

3629
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
67,981✔
3630
{
3631
   VCODE_FOR_EACH_OP(other) {
717,610✔
3632
      if (other->kind == VCODE_OP_LOAD_INDIRECT
672,072✔
3633
          && other->args.items[0] == reg) {
93,465✔
3634
         return other->result;
5,014✔
3635
      }
3636
      else if (other->kind == VCODE_OP_FCALL
667,058✔
3637
               || other->kind == VCODE_OP_PCALL
667,058✔
3638
               || other->kind == VCODE_OP_STORE
662,880✔
3639
               || other->kind == VCODE_OP_STORE_INDIRECT
654,846✔
3640
               || other->kind == VCODE_OP_MEMSET
652,300✔
3641
               || other->kind == VCODE_OP_COPY
652,068✔
3642
               || other->kind == VCODE_OP_FILE_READ)
649,641✔
3643
         break;   // May write to this pointer
3644
   }
3645

3646
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
62,967✔
3647
   vcode_add_arg(op, reg);
62,967✔
3648

3649
   vcode_type_t rtype = vcode_reg_type(reg);
62,967✔
3650

3651
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
62,967✔
3652
                "load indirect with non-pointer argument");
3653

3654
   vcode_type_t deref = vtype_pointed(rtype);
62,967✔
3655
   op->result = vcode_add_reg(deref);
62,967✔
3656

3657
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
62,967✔
3658

3659
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
62,967✔
3660

3661
   return op->result;
62,967✔
3662
}
3663

3664
void emit_store(vcode_reg_t reg, vcode_var_t var)
47,864✔
3665
{
3666
   // Any previous store to this variable in this block is dead
3667
   VCODE_FOR_EACH_OP(other) {
820,622✔
3668
      if (other->kind == VCODE_OP_STORE && other->address == var) {
783,773✔
3669
         other->kind = VCODE_OP_COMMENT;
245✔
3670
         other->comment =
490✔
3671
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
245✔
3672
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
245✔
3673
      }
3674
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
783,528✔
3675
         break;   // Needs to get variable for display
3676
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
777,457✔
3677
               && other->address == var)
16,801✔
3678
         break;   // Previous value may be used
3679
   }
3680

3681
   var_t *v = vcode_var_data(var);
47,864✔
3682
   reg_t *r = vcode_reg_data(reg);
47,864✔
3683

3684
   op_t *op = vcode_add_op(VCODE_OP_STORE);
47,864✔
3685
   vcode_add_arg(op, reg);
47,864✔
3686
   op->address = var;
47,864✔
3687

3688
   VCODE_ASSERT(vtype_eq(v->type, r->type),
47,864✔
3689
                "variable and stored value do not have same type");
3690
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
47,864✔
3691
}
47,864✔
3692

3693
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
10,005✔
3694
{
3695
   reg_t *p = vcode_reg_data(ptr);
10,005✔
3696
   reg_t *r = vcode_reg_data(reg);
10,005✔
3697

3698
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
10,005✔
3699
   vcode_add_arg(op, reg);
10,005✔
3700
   vcode_add_arg(op, ptr);
10,005✔
3701

3702
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
10,005✔
3703
                "store indirect target is not a pointer");
3704
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
10,005✔
3705
                "pointer and stored value do not have same type");
3706
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
10,005✔
3707
}
10,005✔
3708

3709
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
41,895✔
3710
                              vcode_reg_t locus)
3711
{
3712
   // Reuse any previous operation in this block with the same arguments
3713
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,005,670✔
3714
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
57,703✔
3715
         return other->result;
2,344✔
3716
   }
3717

3718
   op_t *op = vcode_add_op(kind);
39,551✔
3719
   vcode_add_arg(op, lhs);
39,551✔
3720
   vcode_add_arg(op, rhs);
39,551✔
3721
   if (locus != VCODE_INVALID_REG)
39,551✔
3722
      vcode_add_arg(op, locus);
4,722✔
3723

3724
   op->result = vcode_add_reg(vcode_reg_type(lhs));
39,551✔
3725

3726
   vcode_type_t lhs_type = vcode_reg_type(lhs);
39,551✔
3727
   vcode_type_t rhs_type = vcode_reg_type(rhs);
39,551✔
3728

3729
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
39,551✔
3730
                "arguments to %s are not the same type", vcode_op_string(kind));
3731

3732
   return op->result;
3733
}
3734

3735
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
29,291✔
3736
                               vcode_reg_t locus)
3737
{
3738
   int64_t lconst, rconst;
29,291✔
3739
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
29,291✔
3740
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
29,291✔
3741
   if (l_is_const && r_is_const)
29,291✔
3742
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
17,659✔
3743
   else if (r_is_const && rconst == 1)
11,632✔
3744
      return lhs;
3745
   else if (l_is_const && lconst == 1)
2,911✔
3746
      return rhs;
3747
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
2,639✔
3748
      return emit_const(vcode_reg_type(lhs), 0);
36✔
3749

3750
   reg_t *lhs_r = vcode_reg_data(lhs);
2,603✔
3751
   reg_t *rhs_r = vcode_reg_data(rhs);
2,603✔
3752

3753
   vtype_t *bl = vcode_type_data(lhs_r->bounds);
2,603✔
3754
   vtype_t *br = vcode_type_data(rhs_r->bounds);
2,603✔
3755

3756
   vcode_type_t vbounds;
2,603✔
3757
   if (vcode_reg_kind(lhs) == VCODE_TYPE_REAL) {
2,603✔
3758
      const double ll = bl->rlow * br->rlow;
711✔
3759
      const double lh = bl->rlow * br->rhigh;
711✔
3760
      const double hl = bl->rhigh * br->rlow;
711✔
3761
      const double hh = bl->rhigh * br->rhigh;
711✔
3762

3763
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,539✔
3764
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,749✔
3765

3766
      vbounds = vtype_real(min, max);
711✔
3767
   }
3768
   else {
3769
      const int64_t ll = smul64(bl->low, br->low);
1,892✔
3770
      const int64_t lh = smul64(bl->low, br->high);
1,892✔
3771
      const int64_t hl = smul64(bl->high, br->low);
1,892✔
3772
      const int64_t hh = smul64(bl->high, br->high);
1,892✔
3773

3774
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
1,892✔
3775
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
1,892✔
3776

3777
      vtype_repr_t repr = vtype_repr(lhs_r->type);
1,892✔
3778
      if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
1,892✔
3779
         op = VCODE_OP_MUL;   // Cannot overflow
363✔
3780
         locus = VCODE_INVALID_REG;
363✔
3781
      }
3782

3783
      vbounds = vtype_int(min, max);
1,892✔
3784
   }
3785

3786
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
2,603✔
3787

3788
   if (vbounds != VCODE_INVALID_TYPE)
2,603✔
3789
      vcode_reg_data(reg)->bounds = vbounds;
2,603✔
3790

3791
   return reg;
3792
}
3793

3794
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
28,493✔
3795
{
3796
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
28,493✔
3797
}
3798

3799
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
798✔
3800
{
3801
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
798✔
3802

3803
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
798✔
3804
                "trapping add may only be used with integer types");
3805

3806
   return result;
798✔
3807
}
3808

3809
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
561✔
3810
{
3811
   int64_t lconst, rconst;
561✔
3812
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
561✔
3813
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
561✔
3814
   if (l_is_const && r_is_const && rconst != 0)
561✔
3815
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
3✔
3816
   else if (r_is_const && rconst == 1)
558✔
3817
      return lhs;
3818

3819
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
557✔
3820

3821
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
557✔
3822

3823
   if (bl->kind == VCODE_TYPE_INT && r_is_const && rconst != 0) {
557✔
3824
      reg_t *rr = vcode_reg_data(reg);
283✔
3825
      rr->bounds = vtype_int(bl->low / rconst, bl->high / rconst);
283✔
3826
   }
3827
   else if (bl->kind == VCODE_TYPE_REAL) {
274✔
3828
      reg_t *rr = vcode_reg_data(reg);
209✔
3829
      rr->bounds = vtype_real(-INFINITY, INFINITY);
209✔
3830
   }
3831

3832
   return reg;
3833
}
3834

3835
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
78✔
3836
{
3837
   int64_t lconst, rconst;
78✔
3838
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
78✔
3839
       && rconst >= 0)
×
3840
      return emit_const(vcode_reg_type(lhs), ipow(lconst, rconst));
×
3841

3842
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
78✔
3843
}
3844

3845
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
538✔
3846
{
3847
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
538✔
3848

3849
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
538✔
3850
                "trapping exp may only be used with integer types");
3851

3852
   return result;
538✔
3853
}
3854

3855
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
183✔
3856
{
3857
   int64_t lconst, rconst;
183✔
3858
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
183✔
3859
       && lconst > 0 && rconst > 0)
14✔
3860
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
3✔
3861

3862
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
180✔
3863
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
180✔
3864

3865
   if (bl->low >= 0 && br->low >= 0) {
180✔
3866
      // If both arguments are non-negative then rem is equivalent and
3867
      // cheaper to compute
3868
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
27✔
3869

3870
      reg_t *rr = vcode_reg_data(reg);
27✔
3871
      rr->bounds = vtype_int(0, br->high - 1);
27✔
3872

3873
      return reg;
27✔
3874
   }
3875
   else
3876
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
153✔
3877
}
3878

3879
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
71✔
3880
{
3881
   int64_t lconst, rconst;
71✔
3882
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
71✔
3883
       && lconst > 0 && rconst > 0)
2✔
3884
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
3885

3886
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
71✔
3887

3888
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
71✔
3889
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
71✔
3890

3891
   if (bl->low >= 0 && br->low >= 0) {
71✔
3892
      reg_t *rr = vcode_reg_data(reg);
15✔
3893
      rr->bounds = vtype_int(0, br->high - 1);
15✔
3894
   }
3895

3896
   return reg;
3897
}
3898

3899
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
37,402✔
3900
                               vcode_reg_t locus)
3901
{
3902
   int64_t lconst, rconst;
37,402✔
3903
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
37,402✔
3904
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
37,402✔
3905
   if (l_is_const && r_is_const)
37,402✔
3906
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
16,793✔
3907
   else if (r_is_const && rconst == 0)
20,609✔
3908
      return lhs;
3909
   else if (l_is_const && lconst == 0)
20,591✔
3910
      return rhs;
3911

3912
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
13,092✔
3913
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
13,092✔
3914
      reg_t *lhs_r = vcode_reg_data(lhs);
12,844✔
3915
      reg_t *rhs_r = vcode_reg_data(rhs);
12,844✔
3916

3917
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
12,844✔
3918
      vtype_t *br = vcode_type_data(rhs_r->bounds);
12,844✔
3919

3920
      int64_t rbl = sadd64(bl->low, br->low);
12,844✔
3921
      int64_t rbh = sadd64(bl->high, br->high);
12,844✔
3922

3923
      vtype_repr_t repr = vtype_repr(lhs_r->type);
12,844✔
3924
      if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
12,844✔
3925
         op = VCODE_OP_ADD;   // Cannot overflow
751✔
3926
         locus = VCODE_INVALID_REG;
751✔
3927
      }
3928

3929
      vbounds = vtype_int(rbl, rbh);
12,844✔
3930
   }
3931

3932
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
13,092✔
3933

3934
   if (vbounds != VCODE_INVALID_TYPE)
13,092✔
3935
      vcode_reg_data(reg)->bounds = vbounds;
12,844✔
3936

3937
   return reg;
3938
}
3939

3940
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
34,706✔
3941
{
3942
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
34,706✔
3943
}
3944

3945
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
2,696✔
3946
{
3947
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
2,696✔
3948

3949
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
2,696✔
3950
                "trapping add may only be used with integer types");
3951

3952
   return result;
2,696✔
3953
}
3954

3955
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
31,940✔
3956
                               vcode_reg_t locus)
3957
{
3958
   int64_t lconst, rconst;
31,940✔
3959
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
31,940✔
3960
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
31,940✔
3961
   if (l_is_const && r_is_const)
31,940✔
3962
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
11,604✔
3963
   else if (r_is_const && rconst == 0)
20,336✔
3964
      return lhs;
3965
   else if (l_is_const && lconst == 0)
18,854✔
3966
      return emit_neg(rhs);
717✔
3967

3968
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
18,137✔
3969
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
18,137✔
3970
      reg_t *lhs_r = vcode_reg_data(lhs);
17,848✔
3971
      reg_t *rhs_r = vcode_reg_data(rhs);
17,848✔
3972

3973
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
17,848✔
3974
      vtype_t *br = vcode_type_data(rhs_r->bounds);
17,848✔
3975

3976
      int64_t rbl = ssub64(bl->low, br->high);
17,848✔
3977
      int64_t rbh = ssub64(bl->high, br->low);
17,848✔
3978

3979
      vtype_repr_t repr = vtype_repr(lhs_r->type);
17,848✔
3980
      if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
17,848✔
3981
         op = VCODE_OP_SUB;   // Cannot overflow
2,311✔
3982
         locus = VCODE_INVALID_REG;
2,311✔
3983
      }
3984

3985
      vbounds = vtype_int(rbl, rbh);
17,848✔
3986
   }
3987

3988
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
18,137✔
3989

3990
   if (vbounds != VCODE_INVALID_TYPE)
18,137✔
3991
      vcode_reg_data(reg)->bounds = vbounds;
17,848✔
3992

3993
   return reg;
3994
}
3995

3996
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
27,403✔
3997
{
3998
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
27,403✔
3999
}
4000

4001
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
4,537✔
4002
{
4003
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
4,537✔
4004

4005
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
4,537✔
4006
                "trapping sub may only be used with integer types");
4007

4008
   return result;
4,537✔
4009
}
4010

4011
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
4012
{
4013
   switch (vtype_kind(var->type)) {
4014
   case VCODE_TYPE_CARRAY:
4015
      op->type = vtype_pointer(vtype_elem(var->type));
4016
      op->result = vcode_add_reg(op->type);
4017
      vcode_reg_data(op->result)->bounds = vtype_bounds(var->type);
4018
      break;
4019

4020
   case VCODE_TYPE_RECORD:
4021
      op->type = vtype_pointer(var->type);
4022
      op->result = vcode_add_reg(op->type);
4023
      break;
4024

4025
   case VCODE_TYPE_INT:
4026
   case VCODE_TYPE_FILE:
4027
   case VCODE_TYPE_ACCESS:
4028
   case VCODE_TYPE_REAL:
4029
   case VCODE_TYPE_UARRAY:
4030
   case VCODE_TYPE_POINTER:
4031
   case VCODE_TYPE_SIGNAL:
4032
   case VCODE_TYPE_CONTEXT:
4033
   case VCODE_TYPE_OFFSET:
4034
   case VCODE_TYPE_TRIGGER:
4035
      op->type = vtype_pointer(var->type);
4036
      op->result = vcode_add_reg(op->type);
4037
      vcode_reg_data(op->result)->bounds = var->bounds;
4038
      break;
4039

4040
   default:
4041
      VCODE_ASSERT(false, "variable %s cannot be indexed",
4042
                   istr(var->name));
4043
   }
4044
}
4045

4046
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
19,023✔
4047
{
4048
   // Try to find a previous index of this var by this offset
4049
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
623,628✔
4050
      if (other->address == var
37,405✔
4051
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
5,374✔
4052
              || (offset != VCODE_INVALID_REG
×
4053
                  && other->args.items[0] == offset)))
×
4054
         return other->result;
5,374✔
4055
   }
4056

4057
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
13,649✔
4058
   op->address = var;
13,649✔
4059

4060
   if (offset != VCODE_INVALID_REG)
13,649✔
4061
      vcode_add_arg(op, offset);
×
4062

4063
   vcode_calculate_var_index_type(op, vcode_var_data(var));
13,649✔
4064

4065
   if (offset != VCODE_INVALID_REG)
13,649✔
4066
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4067
                   "index offset r%d does not have offset type", offset);
4068

4069
   return op->result;
13,649✔
4070
}
4071

4072
vcode_reg_t emit_cast(vcode_type_t type, vcode_type_t bounds, vcode_reg_t reg)
79,222✔
4073
{
4074
   if (vtype_eq(vcode_reg_type(reg), type))
79,222✔
4075
      return reg;
79,222✔
4076

4077
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
61,945✔
4078
   vtype_kind_t to   = vtype_kind(type);
61,945✔
4079

4080
   const bool integral =
123,890✔
4081
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
61,945✔
4082
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
61,945✔
4083

4084
   int64_t value;
61,945✔
4085
   if (integral && vcode_reg_const(reg, &value))
61,945✔
4086
      return emit_const(type, value);
12,289✔
4087

4088
   // Try to find a previous cast of this register to this type
4089
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
897,655✔
4090
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
107,128✔
4091
         return other->result;
10,524✔
4092
   }
4093

4094
   op_t *op = vcode_add_op(VCODE_OP_CAST);
39,132✔
4095
   vcode_add_arg(op, reg);
39,132✔
4096
   op->type   = type;
39,132✔
4097
   op->result = vcode_add_reg(type);
39,132✔
4098

4099
   static const vcode_type_t allowed[][2] = {
39,132✔
4100
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4101
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4102
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4103
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4104
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4105
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4106
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4107
   };
4108

4109
   if (from == VCODE_TYPE_INT && bounds == VCODE_INVALID_TYPE) {
39,132✔
4110
      reg_t *rr = vcode_reg_data(op->result);
7,682✔
4111
      rr->bounds = vcode_reg_bounds(reg);
7,682✔
4112
   }
4113
   else if (to == VCODE_TYPE_INT && bounds != VCODE_INVALID_TYPE) {
31,450✔
4114
      reg_t *rr = vcode_reg_data(op->result);
25,442✔
4115
      rr->bounds = bounds;
25,442✔
4116
   }
4117

4118
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
71,454✔
4119
      if (from == allowed[i][0] && to == allowed[i][1])
71,454✔
4120
         return op->result;
4121
   }
4122

4123
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4124
}
4125

4126
void emit_return(vcode_reg_t reg)
43,680✔
4127
{
4128
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
43,680✔
4129
   if (reg != VCODE_INVALID_REG) {
43,680✔
4130
      vcode_add_arg(op, reg);
24,670✔
4131

4132
      const vtype_kind_t rkind = vcode_reg_kind(reg);
24,670✔
4133
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
24,670✔
4134
         vcode_heap_allocate(reg);
7,710✔
4135
         active_unit->flags |= UNIT_ESCAPING_TLAB;
7,710✔
4136
      }
4137

4138
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
24,670✔
4139
                   || active_unit->kind == VCODE_UNIT_THUNK
4140
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4141
                   "returning value fron non-function unit");
4142
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
24,670✔
4143
                    && rkind == VCODE_TYPE_INT)
4144
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4145
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4146
                       && rkind == VCODE_TYPE_ACCESS),
4147
                   "return value incorrect type");
4148
   }
4149
}
43,680✔
4150

4151
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
8,473✔
4152
                         vcode_reg_t values, vcode_reg_t reject,
4153
                         vcode_reg_t after)
4154
{
4155
   int64_t nconst;
8,473✔
4156
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
8,473✔
4157
      emit_comment("Skip empty waveform");
3✔
4158
      return;
3✔
4159
   }
4160

4161
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
8,470✔
4162
   vcode_add_arg(op, nets);
8,470✔
4163
   vcode_add_arg(op, nnets);
8,470✔
4164
   vcode_add_arg(op, values);
8,470✔
4165
   vcode_add_arg(op, reject);
8,470✔
4166
   vcode_add_arg(op, after);
8,470✔
4167

4168
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
8,470✔
4169
                "sched_waveform target is not signal");
4170
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
8,470✔
4171
                "sched_waveform net count is not offset type");
4172
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
8,470✔
4173
                "signal cannot be values argument for sched_waveform");
4174
}
4175

4176
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
48✔
4177
{
4178
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
48✔
4179
   vcode_add_arg(op, nets);
48✔
4180
   vcode_add_arg(op, nnets);
48✔
4181
   vcode_add_arg(op, values);
48✔
4182

4183
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
48✔
4184
                "force target is not signal");
4185
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
48✔
4186
                "force net count is not offset type");
4187
}
48✔
4188

4189
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
24✔
4190
{
4191
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
24✔
4192
   vcode_add_arg(op, nets);
24✔
4193
   vcode_add_arg(op, nnets);
24✔
4194

4195
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
24✔
4196
                "release target is not signal");
4197
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
24✔
4198
                "release net count is not offset type");
4199
}
24✔
4200

4201
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
15✔
4202
                     vcode_reg_t after)
4203
{
4204
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
15✔
4205
   vcode_add_arg(op, nets);
15✔
4206
   vcode_add_arg(op, nnets);
15✔
4207
   vcode_add_arg(op, reject);
15✔
4208
   vcode_add_arg(op, after);
15✔
4209

4210
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
15✔
4211
                "disconnect target is not signal");
4212
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
15✔
4213
                "disconnect net count is not offset type");
4214
}
15✔
4215

4216
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
31,763✔
4217
{
4218
   int64_t tconst;
31,763✔
4219
   if (vcode_reg_const(test, &tconst)) {
31,763✔
4220
      emit_jump(!!tconst ? btrue : bfalse);
5,576✔
4221
      return;
3,401✔
4222
   }
4223

4224
   op_t *op = vcode_add_op(VCODE_OP_COND);
28,362✔
4225
   vcode_add_arg(op, test);
28,362✔
4226
   vcode_add_target(op, btrue);
28,362✔
4227
   vcode_add_target(op, bfalse);
28,362✔
4228

4229
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
28,362✔
4230
                "cond test is not a bool");
4231
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
28,362✔
4232
                "invalid cond targets");
4233
}
4234

4235
vcode_reg_t emit_neg(vcode_reg_t lhs)
6,624✔
4236
{
4237
   int64_t lconst;
6,624✔
4238
   if (vcode_reg_const(lhs, &lconst))
6,624✔
4239
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4240

4241
   op_t *op = vcode_add_op(VCODE_OP_NEG);
6,624✔
4242
   vcode_add_arg(op, lhs);
6,624✔
4243
   op->result = vcode_add_reg(vcode_reg_type(lhs));
6,624✔
4244

4245
   return op->result;
6,624✔
4246
}
4247

4248
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
768✔
4249
{
4250
   int64_t lconst;
768✔
4251
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
768✔
4252
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4253
   else if (vcode_type_data(vcode_reg_data(lhs)->bounds)->low >= 0)
768✔
4254
      return emit_neg(lhs);   // Cannot overflow
242✔
4255

4256
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
526✔
4257
   vcode_add_arg(op, lhs);
526✔
4258
   vcode_add_arg(op, locus);
526✔
4259

4260
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
526✔
4261
                "locus argument to trap neg must be a debug locus");
4262
   VCODE_ASSERT(vcode_reg_kind(lhs) == VCODE_TYPE_INT,
526✔
4263
                "trapping neg may only be used with integer types");
4264

4265
   return (op->result = vcode_add_reg(vcode_reg_type(lhs)));
526✔
4266
}
4267

4268
vcode_reg_t emit_abs(vcode_reg_t lhs)
231✔
4269
{
4270
   int64_t lconst;
231✔
4271
   if (vcode_reg_const(lhs, &lconst))
231✔
4272
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4273

4274
   op_t *op = vcode_add_op(VCODE_OP_ABS);
230✔
4275
   vcode_add_arg(op, lhs);
230✔
4276
   op->result = vcode_add_reg(vcode_reg_type(lhs));
230✔
4277

4278
   return op->result;
230✔
4279
}
4280

4281
void emit_comment(const char *fmt, ...)
33,479✔
4282
{
4283
#ifndef NDEBUG
4284
   va_list ap;
33,479✔
4285
   va_start(ap, fmt);
33,479✔
4286
   vcode_add_op(VCODE_OP_COMMENT)->comment = xvasprintf(fmt, ap);
33,479✔
4287
   va_end(ap);
33,479✔
4288
#endif
4289
}
33,479✔
4290

4291
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
14,938✔
4292
                        vcode_reg_t rfalse)
4293
{
4294
   int64_t tconst;
14,938✔
4295
   if (vcode_reg_const(test, &tconst))
14,938✔
4296
      return !!tconst ? rtrue : rfalse;
3,674✔
4297
   else if (rtrue == rfalse)
11,264✔
4298
      return rtrue;
4299

4300
   // Find a previous identical select
4301
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
287,888✔
4302
      if (other->args.items[0] == test && other->args.items[1] == rtrue
11,053✔
4303
          && other->args.items[2] == rfalse)
522✔
4304
         return other->result;
492✔
4305
   }
4306

4307
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
10,595✔
4308
   vcode_add_arg(op, test);
10,595✔
4309
   vcode_add_arg(op, rtrue);
10,595✔
4310
   vcode_add_arg(op, rfalse);
10,595✔
4311
   op->result = vcode_add_reg(vcode_reg_type(rtrue));
10,595✔
4312

4313
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
10,595✔
4314
                "select test must have bool type");
4315
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
10,595✔
4316
                "select arguments are not the same type");
4317

4318
   return op->result;
10,595✔
4319
}
4320

4321
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
91✔
4322
{
4323
   switch (op) {
91✔
4324
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
24✔
4325
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
19✔
4326
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
12✔
4327
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
12✔
4328
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
12✔
4329
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
12✔
4330
   default:
×
4331
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
×
4332
   }
4333
}
4334

4335
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
6,751✔
4336
{
4337
   vcode_type_t vtbool = vtype_bool();
6,751✔
4338

4339
   int64_t lconst, rconst;
6,751✔
4340
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
6,751✔
4341
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
6,751✔
4342
   if (l_is_const && r_is_const) {
6,751✔
4343
      switch (op) {
6✔
4344
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
4345
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
4346
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
×
4347
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
6✔
4348
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
4349
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
4350
      default:
×
4351
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
×
4352
      }
4353
   }
4354
   else if (l_is_const)
6,745✔
4355
      return emit_logical_identity(op, rhs, !!lconst);
12✔
4356
   else if (r_is_const)
6,733✔
4357
      return emit_logical_identity(op, lhs, !!rconst);
79✔
4358
   else if (lhs == rhs) {
6,654✔
4359
      switch (op) {
15✔
4360
      case VCODE_OP_AND:
4361
      case VCODE_OP_OR:
4362
         return lhs;
4363
      case VCODE_OP_NAND:
6✔
4364
      case VCODE_OP_NOR:
4365
         return emit_not(lhs);
6✔
4366
      case VCODE_OP_XOR:
3✔
4367
         return emit_const(vtbool, 0);
3✔
4368
      case VCODE_OP_XNOR:
×
4369
         return emit_const(vtbool, 1);
×
4370
      default:
×
4371
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
×
4372
      }
4373
   }
4374

4375
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
6,639✔
4376

4377
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
6,639✔
4378
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4379
                "arguments to %s are not boolean", vcode_op_string(op));
4380

4381
   return result;
4382
}
4383

4384
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
1,468✔
4385
{
4386
   return emit_logical(VCODE_OP_OR, lhs, rhs);
1,468✔
4387
}
4388

4389
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
4,918✔
4390
{
4391
   return emit_logical(VCODE_OP_AND, lhs, rhs);
4,918✔
4392
}
4393

4394
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
80✔
4395
{
4396
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
80✔
4397
}
4398

4399
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
81✔
4400
{
4401
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
81✔
4402
}
4403

4404
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
119✔
4405
{
4406
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
119✔
4407
}
4408

4409
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
85✔
4410
{
4411
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
85✔
4412
}
4413

4414
vcode_reg_t emit_not(vcode_reg_t arg)
1,942✔
4415
{
4416
   int64_t cval;
1,942✔
4417
   if (vcode_reg_const(arg, &cval))
1,942✔
4418
      return emit_const(vtype_bool(), !cval);
27✔
4419

4420
   op_t *op = vcode_add_op(VCODE_OP_NOT);
1,915✔
4421
   vcode_add_arg(op, arg);
1,915✔
4422

4423
   vcode_type_t vtbool = vtype_bool();
1,915✔
4424
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
1,915✔
4425
                "argument to not is not boolean");
4426

4427
   return (op->result = vcode_add_reg(vtbool));
1,915✔
4428
}
4429

4430
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
41,019✔
4431
{
4432
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,431,930✔
4433
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
160,365✔
4434
         bool match = true;
4435
         for (int i = 0; match && i < ndims; i++) {
12,876✔
4436
            match = other->args.items[i*3 + 1] == dims[i].left
6,458✔
4437
               && other->args.items[i*3 + 2] == dims[i].right
5,366✔
4438
               && other->args.items[i*3 + 3] == dims[i].dir;
11,800✔
4439
         }
4440
         if (match)
6,418✔
4441
            return other->result;
5,302✔
4442
      }
4443
   }
4444

4445
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
35,717✔
4446
   vcode_add_arg(op, data);
35,717✔
4447
   for (int i = 0; i < ndims; i++) {
71,831✔
4448
      vcode_add_arg(op, dims[i].left);
36,114✔
4449
      vcode_add_arg(op, dims[i].right);
36,114✔
4450
      vcode_add_arg(op, dims[i].dir);
36,114✔
4451
   }
4452

4453
   vcode_type_t ptr_type = vcode_reg_type(data);
35,717✔
4454
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
35,717✔
4455
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
35,717✔
4456
                "wrapped data is not pointer or signal");
4457

4458
#ifdef DEBUG
4459
   for (int i = 0; i < ndims; i++) {
71,831✔
4460
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
36,114✔
4461
                   "dimension %d left bound must be scalar", i + 1);
4462
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
36,114✔
4463
                   "dimension %d right bound must be scalar", i + 1);
4464
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
36,114✔
4465
                   "dimension %d direction must be bool", i + 1);
4466
   }
4467
#endif
4468

4469
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
71,434✔
4470
      ? vtype_pointed(ptr_type) : ptr_type;
35,717✔
4471

4472
   op->result = vcode_add_reg(
35,717✔
4473
      vtype_uarray(ndims, elem, vcode_reg_bounds(data)));
4474

4475
   return op->result;
35,717✔
4476
}
4477

4478
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
87,419✔
4479
                                  vcode_reg_t array, unsigned dim,
4480
                                  unsigned arg_index)
4481
{
4482
   // Reuse any previous operation in this block with the same arguments
4483
   VCODE_FOR_EACH_OP(other) {
970,757✔
4484
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
931,339✔
4485
          && (rtype == VCODE_INVALID_TYPE
16,210✔
4486
              || vtype_eq(rtype, vcode_reg_type(other->result))))
6,821✔
4487
         return other->result;
16,210✔
4488
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
915,129✔
4489
         return other->args.items[1 + (dim * 3) + arg_index];
31,791✔
4490
   }
4491

4492
   op_t *op = vcode_add_op(o);
39,418✔
4493
   vcode_add_arg(op, array);
39,418✔
4494
   op->dim = dim;
39,418✔
4495

4496
   vcode_type_t atype = vcode_reg_type(array);
39,418✔
4497
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
39,418✔
4498
                "cannot use %s with non-uarray type", vcode_op_string(o));
4499

4500
   vtype_t *vt = vcode_type_data(atype);
39,418✔
4501
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
39,418✔
4502

4503
   if (rtype == VCODE_INVALID_TYPE)
39,418✔
4504
      rtype = vtype_offset();
25,721✔
4505

4506
   return (op->result = vcode_add_reg(rtype));
39,418✔
4507
}
4508

4509
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
31,451✔
4510
{
4511
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
31,451✔
4512
                         array, dim, 0);
4513
}
4514

4515
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
24,794✔
4516
{
4517
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
24,794✔
4518
                         array, dim, 1);
4519
}
4520

4521
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
31,174✔
4522
{
4523
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
31,174✔
4524
                         array, dim, 2);
4525
}
4526

4527
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
40,353✔
4528
{
4529
   VCODE_FOR_EACH_OP(other) {
353,329✔
4530
      if (other->kind == VCODE_OP_UARRAY_LEN) {
333,140✔
4531
         if (other->args.items[0] == array && other->dim == dim)
27,914✔
4532
            return other->result;
9,576✔
4533
      }
4534
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
305,226✔
4535
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
10,588✔
4536
                      "array dimension %d out of bounds", dim);
4537

4538
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
10,588✔
4539
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
10,588✔
4540
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
10,588✔
4541
         return emit_range_length(left_reg, right_reg, dir_reg);
10,588✔
4542
      }
4543
   }
4544

4545
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
20,189✔
4546
   vcode_add_arg(op, array);
20,189✔
4547
   op->dim = dim;
20,189✔
4548

4549
   vcode_type_t atype = vcode_reg_type(array);
20,189✔
4550
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
20,189✔
4551
                "cannot use uarray len with non-uarray type");
4552

4553
   vtype_t *vt = vcode_type_data(atype);
20,189✔
4554
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
20,189✔
4555

4556
   return (op->result = vcode_add_reg(vtype_offset()));
20,189✔
4557
}
4558

4559
vcode_reg_t emit_unwrap(vcode_reg_t array)
30,293✔
4560
{
4561
   VCODE_FOR_EACH_OP(other) {
559,715✔
4562
      if (other->kind == VCODE_OP_WRAP && other->result == array)
538,356✔
4563
         return other->args.items[0];
8,246✔
4564
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
530,110✔
4565
         return other->result;
688✔
4566
   }
4567

4568
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
21,359✔
4569
   vcode_add_arg(op, array);
21,359✔
4570

4571
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
21,359✔
4572
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
21,359✔
4573
                "unwrap can only only be used with uarray types");
4574

4575
   vcode_type_t elem = vt->elem;
21,359✔
4576

4577
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
21,359✔
4578
      ? elem : vtype_pointer(elem);
21,359✔
4579

4580
   op->result = vcode_add_reg(rtype);
21,359✔
4581

4582
   reg_t *rr = vcode_reg_data(op->result);
21,359✔
4583
   rr->bounds = elem;
21,359✔
4584

4585
   return op->result;
21,359✔
4586
}
4587

4588
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
15,370✔
4589
                            vcode_reg_t dir)
4590
{
4591
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
463,305✔
4592
      if (other->args.items[0] == left
×
4593
          && other->args.items[1] == right
×
4594
          && other->args.items[2] == dir)
×
4595
         return other->result;
×
4596
   }
4597

4598
   int64_t dir_const;
15,370✔
4599
   if (vcode_reg_const(dir, &dir_const)) {
15,370✔
4600
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
11,368✔
4601
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
11,368✔
4602

4603
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
11,368✔
4604
         return emit_const(vtype_bool(), 1);
41✔
4605
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
11,327✔
4606
         return emit_const(vtype_bool(), 0);
5,241✔
4607
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
6,086✔
4608
         return emit_const(vtype_bool(), 1);
71✔
4609
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
6,015✔
4610
         return emit_const(vtype_bool(), 0);
1,474✔
4611
      else if (dir_const == RANGE_TO)
4,541✔
4612
         return emit_cmp(VCODE_CMP_GT, left, right);
1,230✔
4613
      else
4614
         return emit_cmp(VCODE_CMP_GT, right, left);
3,311✔
4615
   }
4616

4617
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
4,002✔
4618
   vcode_add_arg(op, left);
4,002✔
4619
   vcode_add_arg(op, right);
4,002✔
4620
   vcode_add_arg(op, dir);
4,002✔
4621

4622
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
4,002✔
4623
                "range left and right have different types");
4624
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
4,002✔
4625
                "dir argument to range length is not int");
4626

4627
   return (op->result = vcode_add_reg(vtype_bool()));
4,002✔
4628
}
4629

4630
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
14,728✔
4631
                              vcode_reg_t dir)
4632
{
4633
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_LENGTH) {
406,479✔
4634
      if (other->args.items[0] == left
5,195✔
4635
          && other->args.items[1] == right
4,170✔
4636
          && other->args.items[2] == dir)
3,917✔
4637
         return other->result;
3,917✔
4638
   }
4639

4640
   int64_t lconst, rconst, dconst;
10,811✔
4641
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
10,811✔
4642
       && vcode_reg_const(right, &rconst)) {
6,911✔
4643

4644
      int64_t diff;
5,489✔
4645
      if (dconst == RANGE_TO)
5,489✔
4646
         diff = rconst - lconst;
3,860✔
4647
      else
4648
         diff = lconst - rconst;
1,629✔
4649

4650
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
5,489✔
4651
   }
4652

4653
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
5,322✔
4654
   vcode_add_arg(op, left);
5,322✔
4655
   vcode_add_arg(op, right);
5,322✔
4656
   vcode_add_arg(op, dir);
5,322✔
4657

4658
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
5,322✔
4659
                "range left and right have different types");
4660
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
5,322✔
4661
                "dir argument to range length is not int");
4662

4663
   return (op->result = vcode_add_reg(vtype_offset()));
5,322✔
4664
}
4665

4666
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
37,879✔
4667
{
4668
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
570,293✔
4669
      if (other->hops == hops && other->address == var)
67,180✔
4670
         return other->result;
6,052✔
4671
   }
4672

4673
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
31,827✔
4674
   op->hops    = hops;
31,827✔
4675
   op->address = var;
31,827✔
4676

4677
   VCODE_ASSERT(hops > 0, "invalid hop count");
31,827✔
4678

4679
   vcode_unit_t vu = active_unit;
31,827✔
4680
   for (int i = 0; i < hops; i++) {
70,601✔
4681
      vu = vu->context;
38,774✔
4682
      VCODE_ASSERT(vu, "hop count is greater than depth");
38,774✔
4683
   }
4684

4685
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
31,827✔
4686

4687
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
31,827✔
4688

4689
   return op->result;
31,827✔
4690
}
4691

4692
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
8,756✔
4693
                             vcode_reg_t size, vcode_reg_t value,
4694
                             vcode_reg_t flags, vcode_reg_t locus,
4695
                             vcode_reg_t offset)
4696
{
4697
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
8,756✔
4698
   vcode_add_arg(op, count);
8,756✔
4699
   vcode_add_arg(op, size);
8,756✔
4700
   vcode_add_arg(op, value);
8,756✔
4701
   vcode_add_arg(op, flags);
8,756✔
4702
   vcode_add_arg(op, locus);
8,756✔
4703
   if (offset != VCODE_INVALID_REG)
8,756✔
4704
      vcode_add_arg(op, offset);
3,114✔
4705

4706
   vcode_type_t vtype = vcode_reg_type(value);
8,756✔
4707
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
8,756✔
4708
   VCODE_ASSERT(vtype_eq(vtype, type)
8,756✔
4709
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4710
                "init signal value type does not match signal type");
4711
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
8,756✔
4712
                "locus argument to init signal must be a debug locus");
4713
   VCODE_ASSERT(offset == VCODE_INVALID_REG
8,756✔
4714
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4715
                "init signal offset argument must have pointer type");
4716

4717
   return (op->result = vcode_add_reg(vtype_signal(type)));
8,756✔
4718
}
4719

4720
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
2,133✔
4721
{
4722
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
2,133✔
4723
   vcode_add_arg(op, signal);
2,133✔
4724
   vcode_add_arg(op, resolution);
2,133✔
4725

4726
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
2,133✔
4727
                "signal argument has wrong type");
4728
   VCODE_ASSERT(vcode_reg_kind(resolution) == VCODE_TYPE_RESOLUTION,
2,133✔
4729
                "resolution wrapper argument has wrong type");
4730
}
2,133✔
4731

4732
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
21✔
4733
                                 vcode_reg_t size, vcode_reg_t locus,
4734
                                 vcode_reg_t kind, vcode_reg_t closure)
4735
{
4736
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
21✔
4737
   vcode_add_arg(op, count);
21✔
4738
   vcode_add_arg(op, size);
21✔
4739
   vcode_add_arg(op, locus);
21✔
4740
   vcode_add_arg(op, kind);
21✔
4741
   vcode_add_arg(op, closure);
21✔
4742

4743
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
21✔
4744
                "count argument to implicit signal is not offset");
4745
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
21✔
4746
                "kind argument to implicit signal is not offset");
4747
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
21✔
4748
                "closure argument to implicit signal is not a closure");
4749
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
21✔
4750
                "locus argument to implicit signal must be a debug locus");
4751

4752
   return (op->result = vcode_add_reg(vtype_signal(type)));
21✔
4753
}
4754

4755
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t src_count,
920✔
4756
                     vcode_reg_t dst_count, vcode_reg_t conv)
4757
{
4758
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
920✔
4759
   vcode_add_arg(op, src);
920✔
4760
   vcode_add_arg(op, dst);
920✔
4761
   vcode_add_arg(op, src_count);
920✔
4762
   vcode_add_arg(op, dst_count);
920✔
4763
   if (conv != VCODE_INVALID_REG)
920✔
4764
      vcode_add_arg(op, conv);
249✔
4765

4766
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
920✔
4767
                "src argument to map signal is not a signal");
4768
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
920✔
4769
                "dst argument to map signal is not a signal");
4770
   VCODE_ASSERT(vcode_reg_kind(src_count) == VCODE_TYPE_OFFSET,
920✔
4771
                "src count argument type to map signal is not offset");
4772
   VCODE_ASSERT(vcode_reg_kind(dst_count) == VCODE_TYPE_OFFSET,
920✔
4773
                "dst count argument type to map signal is not offset");
4774
   VCODE_ASSERT(conv == VCODE_INVALID_REG
920✔
4775
                || vcode_reg_kind(conv) == VCODE_TYPE_CLOSURE,
4776
                "conv argument type to map signal is not closure");
4777
}
920✔
4778

4779
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
2,401✔
4780
{
4781
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
2,401✔
4782
   vcode_add_arg(op, src);
2,401✔
4783
   vcode_add_arg(op, dst);
2,401✔
4784
   vcode_add_arg(op, count);
2,401✔
4785

4786
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
2,401✔
4787
                "dst argument to map const is not a signal");
4788
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
2,401✔
4789
                "count argument type to map const is not offset");
4790
}
2,401✔
4791

4792
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
7,321✔
4793
{
4794
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
92,564✔
4795
      if (other->args.items[0] == target && other->args.items[1] == count)
13,094✔
4796
         return;
4797
   }
4798

4799
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
7,309✔
4800
   vcode_add_arg(op, target);
7,309✔
4801
   vcode_add_arg(op, count);
7,309✔
4802

4803
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
7,309✔
4804
                "target argument to drive signal is not a signal");
4805
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
7,309✔
4806
                "count argument type to drive signal is not offset");
4807
}
4808

4809
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
1,133✔
4810
                          vcode_reg_t count, vcode_reg_t reject,
4811
                          vcode_reg_t after)
4812
{
4813
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
1,133✔
4814
   vcode_add_arg(op, target);
1,133✔
4815
   vcode_add_arg(op, source);
1,133✔
4816
   vcode_add_arg(op, count);
1,133✔
4817
   vcode_add_arg(op, reject);
1,133✔
4818
   vcode_add_arg(op, after);
1,133✔
4819

4820
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
1,133✔
4821
                "target argument to transfer signal is not a signal");
4822
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
1,133✔
4823
                "count argument type to transfer signal is not offset");
4824
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
1,133✔
4825
                "source argument to transfer signal is not a signal");
4826
}
1,133✔
4827

4828
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
2,022✔
4829
                                    vcode_reg_t ileft, vcode_reg_t nlits)
4830
{
4831
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
101,230✔
4832
      if (other->args.items[0] == closure
1,453✔
4833
          && other->args.items[1] == ileft
1,450✔
4834
          && other->args.items[2] == nlits)
1,450✔
4835
         return other->result;
1,450✔
4836
   }
4837

4838
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
572✔
4839
                "first argument to resolution wrapper must be closure");
4840

4841
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
572✔
4842
   vcode_add_arg(op, closure);
572✔
4843
   vcode_add_arg(op, ileft);
572✔
4844
   vcode_add_arg(op, nlits);
572✔
4845
   op->subkind = VCODE_CC_VHDL;
572✔
4846

4847
   return (op->result = vcode_add_reg(vtype_resolution(type)));
572✔
4848
}
4849

4850
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t atype,
2,181✔
4851
                         vcode_type_t rtype)
4852
{
4853
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
106,089✔
4854
      if (other->func == func && other->subkind == VCODE_CC_VHDL
1,552✔
4855
          && other->args.items[0] == context)
1,471✔
4856
         return other->result;
1,471✔
4857
   }
4858

4859
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
710✔
4860
   vcode_add_arg(op, context);
710✔
4861
   op->func    = func;
710✔
4862
   op->subkind = VCODE_CC_VHDL;
710✔
4863
   op->type    = atype;
710✔
4864

4865
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
710✔
4866
                "invalid closure context argument");
4867

4868
   return (op->result = vcode_add_reg(vtype_closure(rtype)));
710✔
4869
}
4870

4871
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
24,339✔
4872
{
4873
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
33,842✔
4874
      if (other->func == name && other->subkind == VCODE_CC_VHDL)
18,891✔
4875
         return other->result;
10,616✔
4876
   }
4877

4878
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
13,723✔
4879
   op->func    = name;
13,723✔
4880
   op->subkind = VCODE_CC_VHDL;
13,723✔
4881
   if (context != VCODE_INVALID_REG)
13,723✔
4882
      vcode_add_arg(op, context);
130✔
4883

4884
   VCODE_ASSERT(context == VCODE_INVALID_REG
13,723✔
4885
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
4886
                "invalid protected init context argument");
4887
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
13,723✔
4888
                || active_unit->kind == VCODE_UNIT_PACKAGE
4889
                || active_unit->kind == VCODE_UNIT_THUNK,
4890
                "cannot use package init here");
4891
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
13,723✔
4892

4893
   return (op->result = vcode_add_reg(vtype_context(name)));
13,723✔
4894
}
4895

4896
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
145✔
4897
                                vcode_reg_t path_name, vcode_reg_t inst_name)
4898
{
4899
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
145✔
4900
   vcode_add_arg(op, context);
145✔
4901
   op->func    = vtype_name(type);
145✔
4902
   op->subkind = VCODE_CC_VHDL;
145✔
4903

4904
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
145✔
4905
      vcode_add_arg(op, path_name);
32✔
4906
      vcode_add_arg(op, inst_name);
32✔
4907

4908
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
32✔
4909
                   "path name argument must be uarray");
4910
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
32✔
4911
                   "inst name argument must be uarray");
4912
   }
4913

4914
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
145✔
4915
                "protected init type must be context");
4916
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
145✔
4917
                "invalid protected init context argument");
4918

4919
   return (op->result = vcode_add_reg(type));
145✔
4920
}
4921

4922
void emit_process_init(ident_t name, vcode_reg_t locus)
54✔
4923
{
4924
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
54✔
4925
   vcode_add_arg(op, locus);
54✔
4926
   op->func    = name;
54✔
4927
   op->subkind = VCODE_CC_VHDL;
54✔
4928

4929
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
54✔
4930
                "locus argument to process init must be a debug locus");
4931
}
54✔
4932

4933
void emit_protected_free(vcode_reg_t obj)
7✔
4934
{
4935
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
7✔
4936
   vcode_add_arg(op, obj);
7✔
4937

4938
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
7✔
4939
                "protected object type must be context");
4940
}
7✔
4941

4942
vcode_reg_t emit_context_upref(int hops)
14,232✔
4943
{
4944
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
429,640✔
4945
      if (other->hops == hops)
6,428✔
4946
         return other->result;
6,387✔
4947
   }
4948

4949
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
7,845✔
4950
   op->hops = hops;
7,845✔
4951

4952
   VCODE_ASSERT(hops >= 0, "invalid hop count");
7,845✔
4953

4954
   vcode_unit_t vu = active_unit;
7,845✔
4955
   for (int i = 0; i < hops; i++) {
14,841✔
4956
      vu = vu->context;
6,996✔
4957
      VCODE_ASSERT(vu, "hop count is greater than depth");
6,996✔
4958
   }
4959

4960
   return (op->result = vcode_add_reg(vtype_context(vu->name)));
7,845✔
4961
}
4962

4963
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
451✔
4964
                                    vcode_reg_t len)
4965
{
4966
   op_t *op = vcode_add_op(opkind);
451✔
4967
   vcode_add_arg(op, nets);
451✔
4968
   vcode_add_arg(op, len);
451✔
4969

4970
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
451✔
4971
                "argument to %s is not a signal", vcode_op_string(opkind));
4972

4973
   return (op->result = vcode_add_reg(vtype_bool()));
451✔
4974
}
4975

4976
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
261✔
4977
{
4978
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
261✔
4979
}
4980

4981
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
190✔
4982
{
4983
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
190✔
4984
}
4985

4986
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
27,810✔
4987
{
4988
   // Try scanning backwards through the block for another record ref
4989
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
1,795,450✔
4990
      if (other->args.items[0] == record && other->field == field)
386,926✔
4991
         return other->result;
1,748✔
4992
   }
4993

4994
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
26,062✔
4995
   op->field = field;
26,062✔
4996
   vcode_add_arg(op, record);
26,062✔
4997

4998
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
26,062✔
4999

5000
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
26,062✔
5001
                "argument to record ref must be a pointer");
5002

5003
   vtype_t *rtype = vcode_type_data(rptype->pointed);
26,062✔
5004
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
26,062✔
5005
                "argument must be pointer to record or record signal");
5006

5007
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
26,062✔
5008

5009
   vcode_type_t field_type  = rtype->fields.items[field];
26,062✔
5010
   vcode_type_t bounds_type = field_type;
26,062✔
5011
   vcode_type_t result_type = field_type;
26,062✔
5012

5013
   const vtype_kind_t fkind = vtype_kind(field_type);
26,062✔
5014
   if (fkind == VCODE_TYPE_CARRAY)
26,062✔
5015
      result_type = bounds_type = vtype_elem(field_type);
4,483✔
5016
   else if (fkind == VCODE_TYPE_UARRAY) {
21,579✔
5017
      bounds_type = vtype_elem(field_type);
1,760✔
5018
      result_type = field_type;
1,760✔
5019
   }
5020

5021
   op->result = vcode_add_reg(vtype_pointer(result_type));
26,062✔
5022

5023
   reg_t *rr = vcode_reg_data(op->result);
26,062✔
5024
   rr->bounds = bounds_type;
26,062✔
5025

5026
   return op->result;
26,062✔
5027
}
5028

5029
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
28,373✔
5030
{
5031
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
767,821✔
5032
      if (other->args.items[0] == array && other->args.items[1] == offset)
37,996✔
5033
         return other->result;
897✔
5034
   }
5035

5036
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
27,476✔
5037
   vcode_add_arg(op, array);
27,476✔
5038
   vcode_add_arg(op, offset);
27,476✔
5039

5040
   vcode_type_t rtype = vcode_reg_type(array);
27,476✔
5041
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
27,476✔
5042
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5043
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5044
                "argument to array ref must be a pointer or signal");
5045
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
27,476✔
5046
                "array ref offset argument must have offset type");
5047

5048
   op->result = vcode_add_reg(rtype);
27,476✔
5049

5050
   reg_t *rr = vcode_reg_data(op->result);
27,476✔
5051
   rr->bounds = vcode_reg_bounds(array);
27,476✔
5052

5053
   return op->result;
27,476✔
5054
}
5055

5056
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
17,404✔
5057
{
5058
   int64_t cconst;
17,404✔
5059
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
17,404✔
5060
       && cconst == 0)
8,327✔
5061
      return;
4,576✔
5062
   else if (dest == src)
17,284✔
5063
      return;
5064

5065
   op_t *op = vcode_add_op(VCODE_OP_COPY);
12,828✔
5066
   vcode_add_arg(op, dest);
12,828✔
5067
   vcode_add_arg(op, src);
12,828✔
5068
   if (count != VCODE_INVALID_REG)
12,828✔
5069
      vcode_add_arg(op, count);
11,375✔
5070

5071
   vcode_type_t dtype = vcode_reg_type(dest);
12,828✔
5072
   vcode_type_t stype = vcode_reg_type(src);
12,828✔
5073

5074
   vtype_kind_t dkind = vtype_kind(dtype);
12,828✔
5075
   vtype_kind_t skind = vtype_kind(stype);
12,828✔
5076

5077
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
12,828✔
5078
                "destination type is not a pointer or access");
5079
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
12,828✔
5080
                "source type is not a pointer or access");
5081
   VCODE_ASSERT(vtype_eq(dtype, stype),
12,828✔
5082
                "source and destination types do not match");
5083
   VCODE_ASSERT(count == VCODE_INVALID_REG
12,828✔
5084
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5085
                "count is not offset type");
5086

5087
   op->type = vtype_pointed(dtype);
12,828✔
5088
}
5089

5090
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
4,047✔
5091
{
5092
   VCODE_FOR_EACH_OP(other) {
60,011✔
5093
      if (other->kind == VCODE_OP_CLEAR_EVENT)
55,996✔
5094
         break;
5095
      else if (other->kind == VCODE_OP_SCHED_EVENT
55,966✔
5096
               && other->args.items[0] == nets
3,925✔
5097
               && other->args.items[1] == n_elems)
5✔
5098
         return;
5099
   }
5100

5101
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
4,045✔
5102
   vcode_add_arg(op, nets);
4,045✔
5103
   vcode_add_arg(op, n_elems);
4,045✔
5104

5105
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
4,045✔
5106
                "nets argument to sched event must be signal");
5107
}
5108

5109
void emit_implicit_event(vcode_reg_t nets, vcode_reg_t count, vcode_reg_t wake)
18✔
5110
{
5111
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_IMPLICIT_EVENT) {
234✔
5112
      if (other->args.items[0] == nets && other->args.items[1] == count
×
5113
          && other->args.items[1] == wake)
×
5114
         return;
5115
   }
5116

5117
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_EVENT);
18✔
5118
   vcode_add_arg(op, nets);
18✔
5119
   vcode_add_arg(op, count);
18✔
5120
   vcode_add_arg(op, wake);
18✔
5121

5122
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
18✔
5123
                "nets argument to implicit event must be signal");
5124
   VCODE_ASSERT(vcode_reg_kind(wake) == VCODE_TYPE_SIGNAL,
18✔
5125
                "wake argument to implicit event must be signal");
5126
}
5127

5128
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
456✔
5129
{
5130
   VCODE_FOR_EACH_OP(other) {
2,157✔
5131
      if (other->kind == VCODE_OP_SCHED_EVENT)
1,702✔
5132
         break;
5133
      else if (other->kind == VCODE_OP_CLEAR_EVENT
1,702✔
5134
               && other->args.items[0] == nets
43✔
5135
               && other->args.items[1] == n_elems)
1✔
5136
         return;
5137
   }
5138

5139
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
455✔
5140
   vcode_add_arg(op, nets);
455✔
5141
   vcode_add_arg(op, n_elems);
455✔
5142

5143
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
455✔
5144
                "nets argument to clear event must be signal");
5145
}
5146

5147
void emit_resume(ident_t func)
1,971✔
5148
{
5149
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
1,971✔
5150
   op->func = func;
1,971✔
5151

5152
   block_t *b = &(active_unit->blocks.items[active_block]);
1,971✔
5153
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
1,971✔
5154
}
1,971✔
5155

5156
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
5,179✔
5157
{
5158
   int64_t lconst;
5,179✔
5159
   if (vcode_reg_const(len, &lconst) && lconst == 0)
5,179✔
5160
      return;
17✔
5161

5162
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
5,162✔
5163
   vcode_add_arg(op, ptr);
5,162✔
5164
   vcode_add_arg(op, value);
5,162✔
5165
   vcode_add_arg(op, len);
5,162✔
5166

5167
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
5,162✔
5168
                "target of memset must have pointer type");
5169
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
5,162✔
5170
                "value of memset must have scalar type");
5171
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
5,162✔
5172
                "length of memset must have offset type");
5173
}
5174

5175
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
466✔
5176
               const vcode_block_t *blocks, int ncases)
5177
{
5178
   int64_t cval1, cval2;
466✔
5179
   bool is_const = vcode_reg_const(value, &cval1);
466✔
5180

5181
   for (int i = 0; i < ncases; i++) {
4,398✔
5182
      bool can_fold = false;
3,936✔
5183
      if (cases[i] == value)
3,936✔
5184
         can_fold = true;
5185
      else if (is_const && vcode_reg_const(cases[i], &cval2))
3,936✔
5186
         can_fold = (cval1 == cval2);
4✔
5187

5188
      if (can_fold) {
4✔
5189
         emit_jump(blocks[i]);
4✔
5190
         return;
8✔
5191
      }
5192
   }
5193

5194
   if (is_const) {
462✔
5195
      emit_jump(def);
×
5196
      return;
×
5197
   }
5198

5199
   op_t *op = vcode_add_op(VCODE_OP_CASE);
462✔
5200
   vcode_add_arg(op, value);
462✔
5201
   vcode_add_target(op, def);
462✔
5202

5203
   for (int i = 0; i < ncases; i++) {
4,394✔
5204
      vcode_add_arg(op, cases[i]);
3,932✔
5205
      vcode_add_target(op, blocks[i]);
3,932✔
5206

5207
#ifdef DEBUG
5208
      for (int j = 0; j < i; j++)
242,350✔
5209
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
238,418✔
5210
#endif
5211
   }
5212
}
5213

5214
vcode_reg_t emit_endfile(vcode_reg_t file)
27✔
5215
{
5216
   op_t *op = vcode_add_op(VCODE_OP_ENDFILE);
27✔
5217
   vcode_add_arg(op, file);
27✔
5218

5219
   VCODE_ASSERT(vtype_kind(vcode_reg_type(file)) == VCODE_TYPE_FILE,
27✔
5220
                "endfile argument must have file type");
5221

5222
   return (op->result = vcode_add_reg(vtype_bool()));
27✔
5223
}
5224

5225
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
201✔
5226
                    vcode_reg_t kind, vcode_reg_t status)
5227
{
5228
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
201✔
5229
   vcode_add_arg(op, file);
201✔
5230
   vcode_add_arg(op, name);
201✔
5231
   vcode_add_arg(op, length);
201✔
5232
   vcode_add_arg(op, kind);
201✔
5233
   if (status != VCODE_INVALID_REG)
201✔
5234
      vcode_add_arg(op, status);
21✔
5235

5236
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
201✔
5237
                "file open first argument must have file pointer type");
5238
}
201✔
5239

5240
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
116✔
5241
{
5242
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
116✔
5243
   vcode_add_arg(op, file);
116✔
5244
   vcode_add_arg(op, value);
116✔
5245
   if (length != VCODE_INVALID_REG)
116✔
5246
      vcode_add_arg(op, length);
68✔
5247

5248
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
116✔
5249
                "file write first argument must have file pointer type");
5250
}
116✔
5251

5252
void emit_file_close(vcode_reg_t file)
136✔
5253
{
5254
   op_t *op = vcode_add_op(VCODE_OP_FILE_CLOSE);
136✔
5255
   vcode_add_arg(op, file);
136✔
5256

5257
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
136✔
5258
                "file close argument must have file pointer type");
5259
}
136✔
5260

5261
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
69✔
5262
                    vcode_reg_t inlen, vcode_reg_t outlen)
5263
{
5264
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
69✔
5265
   vcode_add_arg(op, file);
69✔
5266
   vcode_add_arg(op, ptr);
69✔
5267
   if (inlen != VCODE_INVALID_REG) {
69✔
5268
      vcode_add_arg(op, inlen);
27✔
5269
      if (outlen != VCODE_INVALID_REG)
27✔
5270
         vcode_add_arg(op, outlen);
18✔
5271
   }
5272

5273
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
69✔
5274
                "file read first argument must have file pointer type");
5275
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
69✔
5276
                "file read pointer argument must have pointer type");
5277
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
69✔
5278
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5279
                "file read outlen argument must have pointer type");
5280
}
69✔
5281

5282
vcode_reg_t emit_null(vcode_type_t type)
5,821✔
5283
{
5284
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
97,795✔
5285
      if (vtype_eq(vcode_reg_type(other->result), type))
1,816✔
5286
         return other->result;
758✔
5287
   }
5288

5289
   op_t *op = vcode_add_op(VCODE_OP_NULL);
5,063✔
5290
   op->result = vcode_add_reg(type);
5,063✔
5291

5292
   vtype_kind_t kind = vtype_kind(type);
5,063✔
5293
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
5,063✔
5294
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5295
                "null type must be file, access, context, or pointer");
5296

5297
   return op->result;
5298
}
5299

5300
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
421✔
5301
{
5302
   op_t *op = vcode_add_op(VCODE_OP_NEW);
421✔
5303
   if (length != VCODE_INVALID_REG)
421✔
5304
      vcode_add_arg(op, length);
330✔
5305

5306
   op->result = vcode_add_reg(vtype_access(type));
421✔
5307

5308
   vtype_kind_t kind = vtype_kind(type);
421✔
5309
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
421✔
5310
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5311
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5312
                "new type must be int, real, record, access, or uarray");
5313
   VCODE_ASSERT(length == VCODE_INVALID_REG
421✔
5314
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5315
                "new length must have offset type");
5316

5317
   return op->result;
421✔
5318
}
5319

5320
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
1,755✔
5321
{
5322
   VCODE_FOR_EACH_OP(other) {
144,150✔
5323
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
142,664✔
5324
         return;
5325
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
142,509✔
5326
         return;
5327
   }
5328

5329
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
1,486✔
5330
   vcode_add_arg(op, ptr);
1,486✔
5331
   vcode_add_arg(op, locus);
1,486✔
5332

5333
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
1,486✔
5334
                "null check argument must be an access");
5335
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,486✔
5336
                "locus argument to null check must be a debug locus");
5337
}
5338

5339
void emit_deallocate(vcode_reg_t ptr)
207✔
5340
{
5341
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
207✔
5342
   vcode_add_arg(op, ptr);
207✔
5343

5344
   vcode_type_t ptype = vcode_reg_type(ptr);
207✔
5345
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
207✔
5346
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5347
                "deallocate argument must be pointer to access");
5348
}
207✔
5349

5350
vcode_reg_t emit_all(vcode_reg_t reg)
2,176✔
5351
{
5352
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
158,293✔
5353
      if (other->args.items[0] == reg)
15,247✔
5354
         return other->result;
269✔
5355
   }
5356

5357
   op_t *op = vcode_add_op(VCODE_OP_ALL);
1,907✔
5358
   vcode_add_arg(op, reg);
1,907✔
5359

5360
   vcode_type_t vtype = vcode_reg_type(reg);
1,907✔
5361

5362
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
1,907✔
5363
                "all argument must be an access");
5364

5365
   vcode_type_t pointed = vtype_pointed(vtype);
1,907✔
5366
   op->result = vcode_add_reg(vtype_pointer(pointed));
1,907✔
5367

5368
   reg_t *rr = vcode_reg_data(op->result);
1,907✔
5369
   rr->bounds = pointed;
1,907✔
5370

5371
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
1,907✔
5372
                "cannot dereference opaque type");
5373

5374
   return op->result;
5375
}
5376

5377
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
11,478✔
5378
{
5379
   block_t *b = &(active_unit->blocks.items[active_block]);
11,478✔
5380
   for (int i = b->ops.count - 1; i >= 0; i--) {
363,026✔
5381
      const op_t *other = &(b->ops.items[i]);
352,188✔
5382
      if (other->kind == kind && other->args.items[0] == sig)
352,188✔
5383
         return other->result;
640✔
5384
   }
5385

5386
   op_t *op = vcode_add_op(kind);
10,838✔
5387
   vcode_add_arg(op, sig);
10,838✔
5388

5389
   vcode_type_t stype = vcode_reg_type(sig);
10,838✔
5390
   op->type = stype;
10,838✔
5391

5392
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
10,838✔
5393
                "argument r%d to resolved is not a signal", sig);
5394

5395
   vcode_type_t rtype = vtype_base(stype);
10,838✔
5396

5397
   const vtype_kind_t rkind = vtype_kind(rtype);
10,838✔
5398
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
10,838✔
5399
      rtype = vtype_elem(rtype);
×
5400

5401
   VCODE_ASSERT(vtype_is_scalar(rtype),
10,838✔
5402
                "resolved signal base type must be scalar");
5403

5404
   op->result = vcode_add_reg(vtype_pointer(rtype));
10,838✔
5405

5406
   reg_t *rr = vcode_reg_data(op->result);
10,838✔
5407
   rr->bounds = rtype;
10,838✔
5408

5409
   return op->result;
10,838✔
5410
}
5411

5412
vcode_reg_t emit_resolved(vcode_reg_t sig)
11,437✔
5413
{
5414
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
11,437✔
5415
}
5416

5417
vcode_reg_t emit_last_value(vcode_reg_t sig)
41✔
5418
{
5419
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
41✔
5420
}
5421

5422
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
42✔
5423
{
5424
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
42✔
5425
   vcode_add_arg(op, signal);
42✔
5426
   if (len != VCODE_INVALID_REG)
42✔
5427
      vcode_add_arg(op, len);
30✔
5428

5429
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
42✔
5430
                "signal argument to last event must have signal type");
5431
   VCODE_ASSERT(len == VCODE_INVALID_REG
42✔
5432
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5433
                "length argument to last event must have offset type");
5434

5435
   return (op->result = vcode_add_reg(vtype_time()));
42✔
5436
}
5437

5438
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
36✔
5439
{
5440
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
36✔
5441
   vcode_add_arg(op, signal);
36✔
5442
   if (len != VCODE_INVALID_REG)
36✔
5443
      vcode_add_arg(op, len);
27✔
5444

5445
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5446
                "signal argument to last active must have signal type");
5447
   VCODE_ASSERT(len == VCODE_INVALID_REG
36✔
5448
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5449
                "length argument to last active must have offset type");
5450

5451
   return (op->result = vcode_add_reg(vtype_time()));
36✔
5452
}
5453

5454
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,337✔
5455
{
5456
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,337✔
5457
   vcode_add_arg(op, signal);
4,337✔
5458
   vcode_add_arg(op, locus);
4,337✔
5459

5460
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,337✔
5461
                "signal argument must have signal type");
5462
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
4,337✔
5463
                "locus argument must have debug locus type");
5464
}
4,337✔
5465

5466
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
30✔
5467
{
5468
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
30✔
5469
   vcode_add_arg(op, signal);
30✔
5470
   vcode_add_arg(op, len);
30✔
5471

5472
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
30✔
5473
                "signal argument to last active must have signal type");
5474
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
30✔
5475
                "length argument to last active must have offset type");
5476

5477
   return (op->result = vcode_add_reg(vtype_bool()));
30✔
5478
}
5479

5480
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
24✔
5481
{
5482
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
24✔
5483
   vcode_add_arg(op, signal);
24✔
5484
   if (len != VCODE_INVALID_REG)
24✔
5485
      vcode_add_arg(op, len);
3✔
5486

5487
   vcode_type_t signal_type = vcode_reg_type(signal);
24✔
5488

5489
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
24✔
5490
                "signal argument to last active must have signal type");
5491
   VCODE_ASSERT(len == VCODE_INVALID_REG
24✔
5492
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5493
                "length argument to last active must have offset type");
5494

5495
   vcode_type_t base_type = vtype_base(signal_type);
24✔
5496
   op->result = vcode_add_reg(vtype_pointer(base_type));
24✔
5497

5498
   reg_t *rr = vcode_reg_data(op->result);
24✔
5499
   rr->bounds = base_type;
24✔
5500

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

5504
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
17,762✔
5505
                       vcode_reg_t dim)
5506
{
5507
   if (rlen == llen)
17,762✔
5508
      return;
5509

5510
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
111,941✔
5511
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
1,820✔
5512
         return;
5513
   }
5514

5515
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
5,200✔
5516
   vcode_add_arg(op, llen);
5,200✔
5517
   vcode_add_arg(op, rlen);
5,200✔
5518
   vcode_add_arg(op, locus);
5,200✔
5519
   if (dim != VCODE_INVALID_REG)
5,200✔
5520
      vcode_add_arg(op, dim);
24✔
5521

5522
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
5,200✔
5523
                "locus argument to length check must be a debug locus");
5524
}
5525

5526
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
538✔
5527
{
5528
   int64_t cval;
538✔
5529
   if (vcode_reg_const(exp, &cval) && cval >= 0)
538✔
5530
      return;
33✔
5531

5532
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
3,159✔
5533
      if (other->args.items[0] == exp)
6✔
5534
         return;
5535
   }
5536

5537
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
505✔
5538
   vcode_add_arg(op, exp);
505✔
5539
   vcode_add_arg(op, locus);
505✔
5540

5541
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
505✔
5542
                "exp argument to exponent check must be a integer");
5543
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
505✔
5544
                "locus argument to exponent check must be a debug locus");
5545
}
5546

5547
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
561✔
5548
{
5549
   int64_t cval;
561✔
5550
   if (vcode_reg_const(denom, &cval) && cval != 0)
561✔
5551
      return;
466✔
5552

5553
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
3,469✔
5554
      if (other->args.items[0] == denom)
56✔
5555
         return;
5556
   }
5557

5558
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
95✔
5559
   vcode_add_arg(op, denom);
95✔
5560
   vcode_add_arg(op, locus);
95✔
5561

5562
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
95✔
5563
                "denom argument to zero check must be a integer");
5564
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
95✔
5565
                "locus argument to zero check must be a debug locus");
5566
}
5567

5568
bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
86,261✔
5569
                            vcode_reg_t right, vcode_reg_t dir)
5570
{
5571
   int64_t dconst;
86,261✔
5572
   if (vcode_reg_const(dir, &dconst)) {
86,261✔
5573
      int64_t lconst, rconst;
79,635✔
5574
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
79,635✔
5575
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
71,300✔
5576
            || (dconst == RANGE_DOWNTO && rconst > lconst);
145,945✔
5577

5578
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
74,645✔
5579

5580
         const bool ok_static =
149,290✔
5581
            (dconst == RANGE_TO
5582
             && bounds->low >= lconst && bounds->high <= rconst)
71,300✔
5583
            || (dconst == RANGE_DOWNTO
9,823✔
5584
                && bounds->low >= rconst && bounds->high <= lconst)
3,345✔
5585
            || (!is_null && (reg == left || reg == right));
81,234✔
5586

5587
         return ok_static;
78,493✔
5588
      }
5589
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
4,990✔
5590
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
4,607✔
5591
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
4,607✔
5592

5593
         assert(lbounds->kind == VCODE_TYPE_REAL);
4,607✔
5594
         assert(rbounds->kind == VCODE_TYPE_REAL);
4,607✔
5595

5596
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
4,607✔
5597
         assert(bounds->kind == VCODE_TYPE_REAL);
4,607✔
5598

5599
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
4,607✔
5600
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
3,848✔
5601
            // Covers the complete double range so can never overflow
5602
            return true;
5603
         }
5604
      }
5605
   }
5606

5607
   return false;
5608
}
5609

5610
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
37,511✔
5611
                              vcode_reg_t left, vcode_reg_t right,
5612
                              vcode_reg_t dir, vcode_reg_t locus,
5613
                              vcode_reg_t hint)
5614
{
5615
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,040,500✔
5616
      if (other->args.items[0] == reg && other->args.items[1] == left
11,012✔
5617
          && other->args.items[2] == right && other->args.items[3] == dir)
241✔
5618
         return;
5619
   }
5620

5621
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
37,270✔
5622
      emit_comment("Elided bounds check for r%d", reg);
25,674✔
5623
      return;
25,674✔
5624
   }
5625

5626
   op_t *op = vcode_add_op(kind);
11,596✔
5627
   vcode_add_arg(op, reg);
11,596✔
5628
   vcode_add_arg(op, left);
11,596✔
5629
   vcode_add_arg(op, right);
11,596✔
5630
   vcode_add_arg(op, dir);
11,596✔
5631
   vcode_add_arg(op, locus);
11,596✔
5632
   vcode_add_arg(op, hint);
11,596✔
5633

5634
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
11,596✔
5635
                "locus argument to bounds check must be a debug locus");
5636
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
11,596✔
5637
                "hint argument to bounds check must be a debug locus");
5638
}
5639

5640
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
2,761✔
5641
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5642
{
5643
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
2,761✔
5644
}
2,761✔
5645

5646
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
34,750✔
5647
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5648
{
5649
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
34,750✔
5650
}
34,750✔
5651

5652
void emit_push_scope(vcode_reg_t locus, vcode_type_t type)
1,064✔
5653
{
5654
   op_t *op = vcode_add_op(VCODE_OP_PUSH_SCOPE);
1,064✔
5655
   vcode_add_arg(op, locus);
1,064✔
5656
   op->type = type;
1,064✔
5657

5658
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,064✔
5659
                "locus argument to push scope must be a debug locus");
5660
}
1,064✔
5661

5662
void emit_pop_scope(void)
1,064✔
5663
{
5664
   vcode_add_op(VCODE_OP_POP_SCOPE);
1,064✔
5665
}
1,064✔
5666

5667
vcode_reg_t emit_debug_locus(ident_t unit, ptrdiff_t offset)
89,148✔
5668
{
5669
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
3,033,710✔
5670
      if (other->ident == unit && other->tag == offset)
353,193✔
5671
         return other->result;
4,473✔
5672
   }
5673

5674
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
84,675✔
5675
   op->ident = unit;
84,675✔
5676
   op->value = offset;
84,675✔
5677

5678
   return (op->result = vcode_add_reg(vtype_debug_locus()));
84,675✔
5679
}
5680

5681
void emit_debug_out(vcode_reg_t reg)
×
5682
{
5683
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
5684
   vcode_add_arg(op, reg);
×
5685
}
×
5686

5687
void emit_cover_stmt(uint32_t tag)
715✔
5688
{
5689
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
715✔
5690
   op->tag = tag;
715✔
5691
}
715✔
5692

5693
void emit_cover_branch(vcode_reg_t test, uint32_t tag, uint32_t flags)
308✔
5694
{
5695
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
308✔
5696
   vcode_add_arg(op, test);
308✔
5697
   op->tag = tag;
308✔
5698
   op->subkind = flags;
308✔
5699
}
308✔
5700

5701
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
281✔
5702
{
5703
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
281✔
5704
   vcode_add_arg(op, signal);
281✔
5705
   op->tag = tag;
281✔
5706
}
281✔
5707

5708
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
12✔
5709
{
5710
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
12✔
5711
   vcode_add_arg(op, signal);
12✔
5712
   vcode_add_arg(op, low);
12✔
5713
   op->tag = tag;
12✔
5714
}
12✔
5715

5716
void emit_cover_expr(vcode_reg_t new_mask, uint32_t tag)
318✔
5717
{
5718
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
318✔
5719
   vcode_add_arg(op, new_mask);
318✔
5720
   op->tag = tag;
318✔
5721
}
318✔
5722

5723
void emit_unreachable(vcode_reg_t locus)
210✔
5724
{
5725
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
210✔
5726
   if (locus != VCODE_INVALID_REG)
210✔
5727
      vcode_add_arg(op, locus);
129✔
5728
}
210✔
5729

5730
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
1,443✔
5731
{
5732
   active_unit->flags |= UNIT_UNDEFINED;
1,443✔
5733

5734
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
1,443✔
5735
   op->result = vcode_add_reg(type);
1,443✔
5736
   vcode_reg_data(op->result)->bounds = bounds;
1,443✔
5737

5738
   return op->result;
1,443✔
5739
}
5740

5741
void emit_debug_info(const loc_t *loc)
1,543,480✔
5742
{
5743
   if (!loc_invalid_p(loc))
1,543,480✔
5744
      vcode_block_data()->last_loc = *loc;
1,467,380✔
5745
}
1,543,480✔
5746

5747
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
3,765✔
5748
{
5749
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
136,081✔
5750
      if (other->args.items[0] == context && other->ident == name)
5,785✔
5751
         return other->result;
1,262✔
5752
   }
5753

5754
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
2,503✔
5755
   vcode_add_arg(op, context);
2,503✔
5756
   op->ident = name;
2,503✔
5757

5758
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
2,503✔
5759
                "first argument to link var must be context");
5760

5761
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
2,503✔
5762
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
79✔
5763
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
79✔
5764
   }
5765
   else {
5766
      op->result = vcode_add_reg(vtype_pointer(type));
2,424✔
5767
      vcode_reg_data(op->result)->bounds = type;
2,424✔
5768
   }
5769

5770
   return op->result;
2,503✔
5771
}
5772

5773
vcode_reg_t emit_link_package(ident_t name)
19,707✔
5774
{
5775
   VCODE_FOR_EACH_OP(other) {
784,914✔
5776
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
774,131✔
5777
         return other->result;
5,507✔
5778
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
768,624✔
5779
         return other->result;
3,417✔
5780
   }
5781

5782
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
10,783✔
5783
   op->ident = name;
10,783✔
5784

5785
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
10,783✔
5786

5787
   return (op->result = vcode_add_reg(vtype_context(name)));
10,783✔
5788
}
5789

5790
vcode_reg_t emit_link_instance(ident_t name, vcode_reg_t locus)
108✔
5791
{
5792
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_INSTANCE) {
510✔
5793
      if (other->ident == name)
39✔
5794
         return other->result;
24✔
5795
   }
5796

5797
   op_t *op = vcode_add_op(VCODE_OP_LINK_INSTANCE);
84✔
5798
   vcode_add_arg(op, locus);
84✔
5799
   op->ident = name;
84✔
5800

5801
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
84✔
5802
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
84✔
5803
                "locus argument to link instance must be a debug locus");
5804

5805
   return (op->result = vcode_add_reg(vtype_context(name)));
84✔
5806
}
5807

5808
void emit_enter_state(vcode_reg_t state)
171✔
5809
{
5810
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
837✔
5811
      if (other->args.items[0] == state)
×
5812
         return;
5813
   }
5814

5815
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
171✔
5816
   vcode_add_arg(op, state);
171✔
5817

5818
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
171✔
5819
                "state must have integer type");
5820
}
5821

5822
vcode_reg_t emit_reflect_value(ident_t ptype, vcode_reg_t value,
45✔
5823
                               vcode_reg_t context, vcode_reg_t locus,
5824
                               vcode_reg_t bounds)
5825
{
5826
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
45✔
5827
   vcode_add_arg(op, value);
45✔
5828
   vcode_add_arg(op, context);
45✔
5829
   vcode_add_arg(op, locus);
45✔
5830
   if (bounds != VCODE_INVALID_REG)
45✔
5831
      vcode_add_arg(op, bounds);
6✔
5832

5833
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
45✔
5834
                "invalid reflect value context argument");
5835
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5836
                "locus argument to reflect value must be a debug locus");
5837

5838
   return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype))));
45✔
5839
}
5840

5841
vcode_reg_t emit_reflect_subtype(ident_t ptype, vcode_reg_t context,
42✔
5842
                                 vcode_reg_t locus, vcode_reg_t bounds)
5843
{
5844
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
5845
   vcode_add_arg(op, context);
42✔
5846
   vcode_add_arg(op, locus);
42✔
5847
   if (bounds != VCODE_INVALID_REG)
42✔
5848
      vcode_add_arg(op, bounds);
×
5849

5850
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
5851
                "invalid reflect value context argument");
5852
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
5853
                "locus argument to reflect value must be a debug locus");
5854

5855
   return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype))));
42✔
5856
}
5857

5858
vcode_reg_t emit_function_trigger(vcode_reg_t closure)
18✔
5859
{
5860
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
18✔
5861
   vcode_add_arg(op, closure);
18✔
5862

5863
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
18✔
5864
                "argument to function trigger must be a closure");
5865

5866
   return (op->result = vcode_add_reg(vtype_trigger()));
18✔
5867
}
5868

5869
void emit_add_trigger(vcode_reg_t trigger)
81✔
5870
{
5871
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
81✔
5872
   vcode_add_arg(op, trigger);
81✔
5873

5874
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
81✔
5875
                "add trigger argument must be trigger");
5876
}
81✔
5877

5878
static void vcode_write_unit(vcode_unit_t unit, fbuf_t *f,
×
5879
                             ident_wr_ctx_t ident_wr_ctx,
5880
                             loc_wr_ctx_t *loc_wr_ctx)
5881
{
5882
   write_u8(unit->kind, f);
×
5883
   ident_write(unit->name, ident_wr_ctx);
×
5884
   fbuf_put_int(f, unit->result);
×
5885
   fbuf_put_int(f, unit->flags);
×
5886
   fbuf_put_int(f, unit->depth);
×
5887

5888
   if (unit->offset < 0) {
×
5889
      object_t *obj = object_from_locus(unit->module, unit->offset, NULL);
×
5890
      object_locus(obj, &unit->module, &unit->offset);
×
5891
   }
5892

5893
   ident_write(unit->module, ident_wr_ctx);
×
5894
   fbuf_put_uint(f, unit->offset);
×
5895

5896
   if (unit->context != NULL) {
×
5897
      vcode_select_unit(unit);
×
5898
      vcode_select_unit(vcode_unit_context());
×
5899
      ident_write(vcode_unit_name(), ident_wr_ctx);
×
5900
      vcode_close();
×
5901
   }
5902
   else
5903
      ident_write(NULL, ident_wr_ctx);
×
5904

5905
   fbuf_put_uint(f, unit->blocks.count);
×
5906
   for (unsigned i = 0; i < unit->blocks.count; i++) {
×
5907
      const block_t *b = &(unit->blocks.items[i]);
×
5908
      fbuf_put_uint(f, b->ops.count);
×
5909

5910
      for (unsigned j = 0; j < b->ops.count; j++) {
×
5911
         op_t *op = &(b->ops.items[j]);
×
5912

5913
         if (op->kind == VCODE_OP_DEBUG_LOCUS)
×
5914
            object_fixup_locus(op->ident, &op->value);
×
5915

5916
         fbuf_put_uint(f, op->kind);
×
5917
         fbuf_put_uint(f, op->result);
×
5918
         loc_write(&(op->loc), loc_wr_ctx);
×
5919

5920
         fbuf_put_uint(f, op->args.count);
×
5921
         for (unsigned k = 0; k < op->args.count; k++)
×
5922
            fbuf_put_uint(f, op->args.items[k]);
×
5923

5924
         if (OP_HAS_TARGET(op->kind)) {
×
5925
            fbuf_put_uint(f, op->targets.count);
×
5926
            for (unsigned k = 0; k < op->targets.count; k++)
×
5927
               fbuf_put_uint(f, op->targets.items[k]);
×
5928
         }
5929

5930
         if (OP_HAS_TYPE(op->kind))
×
5931
            fbuf_put_uint(f, op->type);
×
5932
         if (OP_HAS_ADDRESS(op->kind))
×
5933
            fbuf_put_uint(f, op->address);
×
5934
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
×
5935
            ident_write(op->func, ident_wr_ctx);
×
5936
         if (OP_HAS_SUBKIND(op->kind))
×
5937
            fbuf_put_uint(f, op->subkind);
×
5938
         if (OP_HAS_CMP(op->kind))
×
5939
            fbuf_put_uint(f, op->cmp);
×
5940
         if (OP_HAS_VALUE(op->kind))
×
5941
            fbuf_put_int(f, op->value);
×
5942
         if (OP_HAS_REAL(op->kind))
×
5943
            write_double(op->real, f);
×
5944
         if (OP_HAS_COMMENT(op->kind))
×
5945
            ;   // Do not save comments
5946
         if (OP_HAS_DIM(op->kind))
×
5947
            fbuf_put_uint(f, op->dim);
×
5948
         if (OP_HAS_HOPS(op->kind))
×
5949
            fbuf_put_uint(f, op->hops);
×
5950
         if (OP_HAS_FIELD(op->kind))
×
5951
            fbuf_put_uint(f, op->field);
×
5952
         if (OP_HAS_TAG(op->kind))
×
5953
            fbuf_put_uint(f, op->tag);
×
5954
      }
5955
   }
5956

5957
   fbuf_put_uint(f, unit->regs.count);
×
5958
   for (unsigned i = 0; i < unit->regs.count; i++) {
×
5959
      const reg_t *r = &(unit->regs.items[i]);
×
5960
      fbuf_put_uint(f, r->type);
×
5961
      fbuf_put_uint(f, r->bounds);
×
5962
   }
5963

5964
   fbuf_put_uint(f, unit->types.count);
×
5965
   for (unsigned i = 0; i < unit->types.count; i++) {
×
5966
      const vtype_t *t = &(unit->types.items[i]);
×
5967
      fbuf_put_uint(f, t->kind);
×
5968
      switch (t->kind) {
×
5969
      case VCODE_TYPE_INT:
×
5970
      case VCODE_TYPE_OFFSET:
5971
         fbuf_put_int(f, t->repr);
×
5972
         fbuf_put_int(f, t->low);
×
5973
         fbuf_put_int(f, t->high);
×
5974
         break;
×
5975

5976
      case VCODE_TYPE_REAL:
×
5977
         write_double(t->rlow, f);
×
5978
         write_double(t->rhigh, f);
×
5979
         break;
×
5980

5981
      case VCODE_TYPE_CARRAY:
×
5982
      case VCODE_TYPE_UARRAY:
5983
         fbuf_put_uint(f, t->dims);
×
5984
         fbuf_put_uint(f, t->size);
×
5985
         fbuf_put_uint(f, t->elem);
×
5986
         fbuf_put_uint(f, t->bounds);
×
5987
         break;
×
5988

5989
      case VCODE_TYPE_ACCESS:
×
5990
      case VCODE_TYPE_POINTER:
5991
         fbuf_put_uint(f, t->pointed);
×
5992
         break;
×
5993

5994
      case VCODE_TYPE_FILE:
×
5995
      case VCODE_TYPE_SIGNAL:
5996
      case VCODE_TYPE_RESOLUTION:
5997
      case VCODE_TYPE_CLOSURE:
5998
         fbuf_put_uint(f, t->base);
×
5999
         break;
×
6000

6001
      case VCODE_TYPE_OPAQUE:
6002
      case VCODE_TYPE_DEBUG_LOCUS:
6003
      case VCODE_TYPE_TRIGGER:
6004
         break;
6005

6006
      case VCODE_TYPE_CONTEXT:
×
6007
         ident_write(t->name, ident_wr_ctx);
×
6008
         break;
×
6009

6010
      case VCODE_TYPE_RECORD:
×
6011
         ident_write(t->name, ident_wr_ctx);
×
6012
         fbuf_put_uint(f, t->fields.count);
×
6013
         for (unsigned j = 0; j < t->fields.count; j++)
×
6014
            fbuf_put_uint(f, t->fields.items[j]);
×
6015
         break;
6016
      }
6017
   }
×
6018

6019
   fbuf_put_uint(f, unit->vars.count);
×
6020
   for (unsigned i = 0; i < unit->vars.count; i++) {
×
6021
      const var_t *v = &(unit->vars.items[i]);
×
6022
      fbuf_put_uint(f, v->type);
×
6023
      fbuf_put_uint(f, v->bounds);
×
6024
      ident_write(v->name, ident_wr_ctx);
×
6025
      fbuf_put_uint(f, v->flags);
×
6026
   }
6027

6028
   fbuf_put_uint(f, unit->params.count);
×
6029
   for (unsigned i = 0; i < unit->params.count; i++) {
×
6030
      const param_t *p = &(unit->params.items[i]);
×
6031
      fbuf_put_uint(f, p->type);
×
6032
      fbuf_put_uint(f, p->bounds);
×
6033
      ident_write(p->name, ident_wr_ctx);
×
6034
      fbuf_put_uint(f, p->reg);
×
6035
   }
6036

6037
   if (unit->next != NULL)
×
6038
      vcode_write_unit(unit->next, f, ident_wr_ctx, loc_wr_ctx);
×
6039

6040
   if (unit->children != NULL)
×
6041
      vcode_write_unit(unit->children, f, ident_wr_ctx, loc_wr_ctx);
6042
}
×
6043

6044
void vcode_write(vcode_unit_t unit, fbuf_t *f, ident_wr_ctx_t ident_ctx,
×
6045
                 loc_wr_ctx_t *loc_ctx)
6046
{
6047
   assert(unit->context == NULL);
×
6048

6049
   write_u8(VCODE_VERSION, f);
×
6050

6051
   vcode_write_unit(unit, f, ident_ctx, loc_ctx);
×
6052
   write_u8(0xff, f);  // End marker
×
6053
}
×
6054

6055
static vcode_unit_t vcode_read_unit(fbuf_t *f, ident_rd_ctx_t ident_rd_ctx,
×
6056
                                    loc_rd_ctx_t *loc_rd_ctx, hash_t *seen)
6057
{
6058
   const uint8_t marker = read_u8(f);
×
6059
   if (marker == 0xff)
×
6060
      return false;
6061

6062
   vcode_unit_t unit = xcalloc(sizeof(struct _vcode_unit));
×
6063
   unit->kind   = marker;
×
6064
   unit->name   = ident_read(ident_rd_ctx);
×
6065
   unit->result = fbuf_get_int(f);
×
6066
   unit->flags  = fbuf_get_int(f);
×
6067
   unit->depth  = fbuf_get_int(f);
×
6068
   unit->module = ident_read(ident_rd_ctx);
×
6069
   unit->offset = fbuf_get_uint(f);
×
6070

6071
   hash_put(seen, unit->name, unit);
×
6072

6073
   ident_t context_name = ident_read(ident_rd_ctx);
×
6074
   if (context_name != NULL) {
×
6075
      unit->context = hash_get(seen, context_name);
×
6076
      if (unit->context == NULL)
×
6077
         fatal("%s references nonexistent context %s", fbuf_file_name(f),
×
6078
               istr(context_name));
6079

6080
      vcode_add_child(unit->context, unit);
×
6081
   }
6082
   else
6083
      unit->context = NULL;
×
6084

6085
   block_array_resize(&(unit->blocks), fbuf_get_uint(f), 0);
×
6086
   for (unsigned i = 0; i < unit->blocks.count; i++) {
×
6087
      block_t *b = &(unit->blocks.items[i]);
×
6088
      op_array_resize(&(b->ops), fbuf_get_uint(f), 0);
×
6089

6090
      for (unsigned j = 0; j < b->ops.count; j++) {
×
6091
         op_t *op = &(b->ops.items[j]);
×
6092

6093
         op->kind = fbuf_get_uint(f);
×
6094
         op->result = fbuf_get_uint(f);
×
6095
         loc_read(&(op->loc), loc_rd_ctx);
×
6096

6097
         vcode_reg_array_resize(&(op->args), fbuf_get_uint(f), 0);
×
6098
         for (unsigned k = 0; k < op->args.count; k++)
×
6099
            op->args.items[k] = fbuf_get_uint(f);
×
6100

6101
         if (OP_HAS_TARGET(op->kind)) {
×
6102
            vcode_block_array_resize(&(op->targets), fbuf_get_uint(f), 0);
×
6103
            for (unsigned k = 0; k < op->targets.count; k++)
×
6104
               op->targets.items[k] = fbuf_get_uint(f);
×
6105
         }
6106

6107
         if (OP_HAS_TYPE(op->kind))
×
6108
            op->type = fbuf_get_uint(f);
×
6109
         if (OP_HAS_ADDRESS(op->kind))
×
6110
            op->address = fbuf_get_uint(f);
×
6111
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
×
6112
            op->func = ident_read(ident_rd_ctx);
×
6113
         if (OP_HAS_SUBKIND(op->kind))
×
6114
            op->subkind = fbuf_get_uint(f);
×
6115
         if (OP_HAS_CMP(op->kind))
×
6116
            op->cmp = fbuf_get_uint(f);
×
6117
         if (OP_HAS_VALUE(op->kind))
×
6118
            op->value = fbuf_get_int(f);
×
6119
         if (OP_HAS_REAL(op->kind))
×
6120
            op->real = read_double(f);
×
6121
         if (OP_HAS_COMMENT(op->kind))
×
6122
            op->comment = NULL;
×
6123
         if (OP_HAS_DIM(op->kind))
×
6124
            op->dim = fbuf_get_uint(f);
×
6125
         if (OP_HAS_HOPS(op->kind))
×
6126
            op->hops = fbuf_get_uint(f);
×
6127
         if (OP_HAS_FIELD(op->kind))
×
6128
            op->field = fbuf_get_uint(f);
×
6129
         if (OP_HAS_TAG(op->kind))
×
6130
            op->tag = fbuf_get_uint(f);
×
6131
      }
6132
   }
6133

6134
   reg_array_resize(&(unit->regs), fbuf_get_uint(f), 0);
×
6135
   for (unsigned i = 0; i < unit->regs.count; i++) {
×
6136
      reg_t *r = &(unit->regs.items[i]);
×
6137
      r->type = fbuf_get_uint(f);
×
6138
      r->bounds = fbuf_get_uint(f);
×
6139
   }
6140

6141
   vtype_array_resize(&(unit->types), fbuf_get_uint(f), 0);
×
6142
   for (unsigned i = 0; i < unit->types.count; i++) {
×
6143
      vtype_t *t = &(unit->types.items[i]);
×
6144
      switch ((t->kind = fbuf_get_uint(f))) {
×
6145
      case VCODE_TYPE_INT:
×
6146
      case VCODE_TYPE_OFFSET:
6147
         t->repr = fbuf_get_int(f);
×
6148
         t->low = fbuf_get_int(f);
×
6149
         t->high = fbuf_get_int(f);
×
6150
         break;
×
6151

6152
      case VCODE_TYPE_REAL:
×
6153
         t->rlow = read_double(f);
×
6154
         t->rhigh = read_double(f);
×
6155
         break;
×
6156

6157
      case VCODE_TYPE_CARRAY:
×
6158
      case VCODE_TYPE_UARRAY:
6159
         t->dims = fbuf_get_uint(f);
×
6160
         t->size = fbuf_get_uint(f);
×
6161
         t->elem = fbuf_get_uint(f);
×
6162
         t->bounds = fbuf_get_uint(f);
×
6163
         break;
×
6164

6165
      case VCODE_TYPE_POINTER:
×
6166
      case VCODE_TYPE_ACCESS:
6167
         t->base = fbuf_get_uint(f);
×
6168
         break;
×
6169

6170
      case VCODE_TYPE_FILE:
×
6171
      case VCODE_TYPE_SIGNAL:
6172
      case VCODE_TYPE_RESOLUTION:
6173
      case VCODE_TYPE_CLOSURE:
6174
         t->base = fbuf_get_uint(f);
×
6175
         break;
×
6176

6177
      case VCODE_TYPE_OPAQUE:
6178
      case VCODE_TYPE_DEBUG_LOCUS:
6179
      case VCODE_TYPE_TRIGGER:
6180
         break;
6181

6182
      case VCODE_TYPE_CONTEXT:
×
6183
         t->name = ident_read(ident_rd_ctx);
×
6184
         break;
×
6185

6186
      case VCODE_TYPE_RECORD:
×
6187
         {
6188
            t->name = ident_read(ident_rd_ctx);
×
6189
            vcode_type_array_resize(&(t->fields), fbuf_get_uint(f), 0);
×
6190
            for (unsigned j = 0; j < t->fields.count; j++)
×
6191
               t->fields.items[j] = fbuf_get_uint(f);
×
6192
            break;
6193
         }
6194
      }
6195
   }
×
6196

6197
   var_array_resize(&(unit->vars), fbuf_get_uint(f), 0);
×
6198
   for (unsigned i = 0; i < unit->vars.count; i++) {
×
6199
      var_t *v = &(unit->vars.items[i]);
×
6200
      v->type = fbuf_get_uint(f);
×
6201
      v->bounds = fbuf_get_uint(f);
×
6202
      v->name = ident_read(ident_rd_ctx);
×
6203
      v->flags = fbuf_get_uint(f);
×
6204
   }
6205

6206
   param_array_resize(&(unit->params), fbuf_get_uint(f), 0);
×
6207
   for (unsigned i = 0; i < unit->params.count; i++) {
×
6208
      param_t *p = &(unit->params.items[i]);
×
6209
      p->type = fbuf_get_uint(f);
×
6210
      p->bounds = fbuf_get_uint(f);
×
6211
      p->name = ident_read(ident_rd_ctx);
×
6212
      p->reg = fbuf_get_uint(f);
×
6213
   }
6214

6215
   return unit;
6216
}
6217

6218
vcode_unit_t vcode_read(fbuf_t *f, ident_rd_ctx_t ident_ctx,
×
6219
                        loc_rd_ctx_t *loc_ctx)
6220
{
6221
   const uint8_t version = read_u8(f);
×
6222
   if (version != VCODE_VERSION) {
×
6223
      diag_t *d = diag_new(DIAG_FATAL, NULL);
×
6224
      diag_printf(d, "%s was created with vcode format version %d "
×
6225
                  "(expected %d)", fbuf_file_name(f), version, VCODE_VERSION);
6226
      diag_hint(d, NULL, "this file was most likely created with an earlier "
×
6227
                "version of " PACKAGE_NAME " and should be reanalysed");
6228
      diag_emit(d);
×
6229
      fatal_exit(EXIT_FAILURE);
×
6230
   }
6231

6232
   hash_t *seen = hash_new(128);
×
6233

6234
   vcode_unit_t vu, root = NULL;
×
6235
   while ((vu = vcode_read_unit(f, ident_ctx, loc_ctx, seen))) {
×
6236
      if (root == NULL)
×
6237
         root = vu;
×
6238
   }
6239

6240
   hash_free(seen);
×
6241
   return root;
×
6242
}
6243

6244
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
29,882✔
6245
{
6246
   vcode_select_unit(vu);
29,882✔
6247

6248
   const int nblocks = vcode_count_blocks();
29,882✔
6249
   for (int i = 0; i < nblocks; i++) {
153,111✔
6250
      vcode_select_block(i);
123,229✔
6251

6252
      const int nops = vcode_count_ops();
123,229✔
6253
      for (int op = 0; op < nops; op++) {
1,585,460✔
6254
         switch (vcode_get_op(op)) {
1,462,230✔
6255
         case VCODE_OP_LINK_PACKAGE:
13,566✔
6256
            (*fn)(vcode_get_ident(op), ctx);
13,566✔
6257
            break;
13,566✔
6258
         case VCODE_OP_FCALL:
52,162✔
6259
         case VCODE_OP_PCALL:
6260
         case VCODE_OP_CLOSURE:
6261
         case VCODE_OP_PROTECTED_INIT:
6262
         case VCODE_OP_PACKAGE_INIT:
6263
            {
6264
               const vcode_cc_t cc = vcode_get_subkind(op);
52,162✔
6265
               if (cc != VCODE_CC_FOREIGN && cc != VCODE_CC_VARIADIC)
52,162✔
6266
                  (*fn)(vcode_get_func(op), ctx);
51,119✔
6267
            }
6268
            break;
6269
         default:
6270
            break;
6271
         }
6272
      }
6273
   }
6274
}
29,882✔
6275

6276
#if VCODE_CHECK_UNIONS
6277
#define OP_USE_COUNT_U0(x)                                              \
6278
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6279
#define OP_USE_COUNT_U1(x)                                              \
6280
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6281
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6282
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6283

6284
__attribute__((constructor))
6285
static void vcode_check_unions(void)
6286
{
6287
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6288
   for (int i = 0; i < 256; i++) {
6289
      assert(OP_USE_COUNT_U0(i) <= 1);
6290
      assert(OP_USE_COUNT_U1(i) <= 1);
6291
   }
6292
}
6293
#endif  // VCODE_CHECK_UNIONS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc