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

nickg / nvc / 6383422048

02 Oct 2023 05:25PM UTC coverage: 91.231% (+0.008%) from 91.223%
6383422048

push

github

nickg
Handle $MOVE with overlapping regions in x86 backend

9 of 9 new or added lines in 1 file covered. (100.0%)

48709 of 53391 relevant lines covered (91.23%)

623692.98 hits per line

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

87.47
/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);
4,879,135✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
201,512✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
38,348✔
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
#define OP_HAS_COMMENT(x)                                               \
78
   (x == VCODE_OP_COMMENT)
79
#define OP_HAS_TARGET(x)                                                \
80
   (x == VCODE_OP_WAIT || x == VCODE_OP_JUMP || x == VCODE_OP_COND      \
81
    || x == VCODE_OP_PCALL || x == VCODE_OP_CASE)
82

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

108
DECLARE_AND_DEFINE_ARRAY(op);
1,375,080✔
109

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

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

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

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

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

161
DECLARE_AND_DEFINE_ARRAY(param);
25,764✔
162
DECLARE_AND_DEFINE_ARRAY(var);
36,494✔
163
DECLARE_AND_DEFINE_ARRAY(reg);
1,111,500✔
164
DECLARE_AND_DEFINE_ARRAY(block);
112,513✔
165
DECLARE_AND_DEFINE_ARRAY(vtype);
2,118,670✔
166

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

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

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

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

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

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

211
#define VCODE_VERSION      31
212
#define VCODE_CHECK_UNIONS 0
213

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

219
static inline int64_t sadd64(int64_t a, int64_t b)
24,614✔
220
{
221
   int64_t result;
24,614✔
222
   if (__builtin_add_overflow(a, b, &result))
24,614✔
223
      return b < 0 ? INT64_MIN : INT64_MAX;
8,624✔
224

225
   return result;
226
}
227

228
static inline int64_t ssub64(int64_t a, int64_t b)
35,316✔
229
{
230
   int64_t result;
35,316✔
231
   if (__builtin_sub_overflow(a, b, &result))
35,316✔
232
      return b > 0 ? INT64_MIN : INT64_MAX;
3,925✔
233

234
   return result;
235
}
236

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

243
   return result;
244
}
245

246
static vcode_reg_t vcode_add_reg(vcode_type_t type)
1,111,500✔
247
{
248
   assert(active_unit != NULL);
1,111,500✔
249

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

256
   return reg;
1,111,500✔
257
}
258

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

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

271
   VCODE_ASSERT(
1,375,080✔
272
      !vcode_block_finished(),
273
      "attempt to add to already finished block %d", active_block);
274

275
   block_t *block = vcode_block_data();
1,375,080✔
276

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

283
   return op;
1,375,080✔
284
}
285

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

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

296
static op_t *vcode_op_data(int op)
11,317,400✔
297
{
298
   assert(active_unit != NULL);
11,317,400✔
299
   assert(active_block != VCODE_INVALID_BLOCK);
11,317,400✔
300

301
   block_t *b = &(active_unit->blocks.items[active_block]);
11,317,400✔
302
   return op_array_nth_ptr(&(b->ops), op);
11,317,400✔
303
}
304

305
static op_t *vcode_find_definition(vcode_reg_t reg)
1,146,500✔
306
{
307
   for (int i = active_block; i >= 0; i--) {
1,193,020✔
308
      block_t *b = &(active_unit->blocks.items[i]);
1,190,210✔
309
      for (int j = b->ops.count - 1; j >= 0; j--) {
21,837,400✔
310
         if (b->ops.items[j].result == reg)
21,790,900✔
311
            return &(b->ops.items[j]);
1,143,700✔
312
      }
313
   }
314

315
   return NULL;
316
}
317

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

335
static reg_t *vcode_reg_data(vcode_reg_t reg)
5,982,660✔
336
{
337
   assert(active_unit != NULL);
5,982,660✔
338
   assert(reg != VCODE_INVALID_REG);
5,982,660✔
339
   return reg_array_nth_ptr(&(active_unit->regs), reg);
5,982,660✔
340
}
341

342
static vtype_t *vcode_type_data(vcode_type_t type)
60,679,700✔
343
{
344
   assert(type != VCODE_INVALID_TYPE);
60,679,700✔
345
   assert(active_unit != NULL);
60,679,700✔
346
   vcode_unit_t unit = active_unit;
60,679,700✔
347

348
   int depth = MASK_CONTEXT(type);
60,679,700✔
349
   assert(depth <= unit->depth);
60,679,700✔
350
   while (depth != unit->depth)
61,620,600✔
351
      unit = unit->context;
940,887✔
352

353
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
60,679,700✔
354
}
355

356
static var_t *vcode_var_data(vcode_var_t var)
340,539✔
357
{
358
   assert(active_unit != NULL);
340,539✔
359
   assert(var != VCODE_INVALID_VAR);
340,539✔
360

361
   return var_array_nth_ptr(&(active_unit->vars), var);
340,539✔
362
}
363

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

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

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

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

396
   case VCODE_OP_VAR_UPREF:
707✔
397
      {
398
         vcode_state_t state;
707✔
399
         vcode_state_save(&state);
707✔
400

401
         for (int i = 0; i < defn->hops; i++)
1,414✔
402
            vcode_select_unit(vcode_unit_context());
707✔
403

404
         vcode_var_data(defn->address)->flags |= VAR_HEAP;
707✔
405
         active_unit->flags |= UNIT_ESCAPING_TLAB;
707✔
406

407
         vcode_state_restore(&state);
707✔
408
      }
409
      break;
707✔
410

411
   case VCODE_OP_ARRAY_REF:
166✔
412
      vcode_heap_allocate(defn->args.items[0]);
166✔
413
      break;
166✔
414

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

421
   case VCODE_OP_LAST_VALUE:
422
      // Returns a pointer into the C heap
423
      break;
424

425
   case VCODE_OP_LOAD:
2,255✔
426
      {
427
         if (vcode_reg_kind(reg) != VCODE_TYPE_UARRAY)
2,255✔
428
            return;
429

430
         // Any store to this variable must be heap allocated
431
         for (int i = 0; i < active_unit->blocks.count; i++) {
21,322✔
432
            block_t *b = &(active_unit->blocks.items[i]);
19,721✔
433
            for (int j = 0; j < b->ops.count; j++) {
282,338✔
434
               op_t *op = &(b->ops.items[j]);
262,617✔
435
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
262,617✔
436
                  vcode_heap_allocate(op->args.items[0]);
1,601✔
437

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

446
   case VCODE_OP_FCALL:
447
      for (int i = 0; i < defn->args.count; i++) {
9,803✔
448
         const vtype_kind_t rkind = vcode_reg_kind(reg);
7,467✔
449
         if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
7,467✔
450
            // Function may return a pointer to its argument
451
            vcode_heap_allocate(defn->args.items[i]);
7,355✔
452
         }
453
      }
454
      break;
455

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

460
   case VCODE_OP_SELECT:
480✔
461
      vcode_heap_allocate(defn->args.items[1]);
480✔
462
      vcode_heap_allocate(defn->args.items[2]);
480✔
463
      break;
480✔
464

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

474
   case VCODE_OP_ALL:
475
      // Must have been allocated on the heap
476
      break;
477

478
   case VCODE_OP_NEW:
479
      // On the heap by definition
480
      break;
481

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

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

521
void vcode_state_save(vcode_state_t *state)
116,320✔
522
{
523
   state->unit  = active_unit;
116,320✔
524
   state->block = active_block;
116,320✔
525
}
116,320✔
526

527
void vcode_state_restore(const vcode_state_t *state)
133,638✔
528
{
529
   active_unit  = state->unit;
133,638✔
530
   active_block = state->block;
133,638✔
531
}
133,638✔
532

533
void vcode_unit_unref(vcode_unit_t unit)
9,481✔
534
{
535
   assert(unit != NULL);
9,481✔
536

537
   if (unit == active_unit)
9,481✔
538
      vcode_close();
9,323✔
539

540
   while (unit->children)
9,481✔
541
      vcode_unit_unref(unit->children);
×
542

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

551
   for (unsigned i = 0; i < unit->blocks.count; i++) {
19,016✔
552
      block_t *b = &(unit->blocks.items[i]);
9,535✔
553

554
      for (unsigned j = 0; j < b->ops.count; j++) {
66,709✔
555
         op_t *o = &(b->ops.items[j]);
57,174✔
556
         if (OP_HAS_COMMENT(o->kind))
57,174✔
557
            free(o->comment);
347✔
558
         if (OP_HAS_TARGET(o->kind))
57,174✔
559
            free(o->targets.items);
27✔
560
         free(o->args.items);
57,174✔
561
      }
562
      free(b->ops.items);
9,535✔
563
   }
564
   free(unit->blocks.items);
9,481✔
565

566
   for (unsigned i = 0; i < unit->types.count; i++) {
58,667✔
567
      vtype_t *vt = &(unit->types.items[i]);
49,186✔
568
      if (vt->kind == VCODE_TYPE_RECORD)
49,186✔
569
         free(vt->fields.items);
103✔
570
   }
571
   free(unit->types.items);
9,481✔
572

573
   free(unit->regs.items);
9,481✔
574
   free(unit->vars.items);
9,481✔
575
   free(unit->params.items);
9,481✔
576
   free(unit);
9,481✔
577
}
9,481✔
578

579
vcode_unit_t vcode_unit_next(vcode_unit_t unit)
18,793✔
580
{
581
   return unit->next;
18,793✔
582
}
583

584
vcode_unit_t vcode_unit_child(vcode_unit_t unit)
21,859✔
585
{
586
   return unit->children;
21,859✔
587
}
588

589
int vcode_count_regs(void)
40,103✔
590
{
591
   assert(active_unit != NULL);
40,103✔
592
   return active_unit->regs.count;
40,103✔
593
}
594

595
vcode_type_t vcode_reg_type(vcode_reg_t reg)
4,083,850✔
596
{
597
   return vcode_reg_data(reg)->type;
4,083,850✔
598
}
599

600
vtype_kind_t vcode_reg_kind(vcode_reg_t reg)
1,093,370✔
601
{
602
   return vtype_kind(vcode_reg_type(reg));
1,093,370✔
603
}
604

605
vcode_type_t vcode_reg_bounds(vcode_reg_t reg)
174,835✔
606
{
607
   return vcode_reg_data(reg)->bounds;
174,835✔
608
}
609

610
bool vcode_reg_const(vcode_reg_t reg, int64_t *value)
716,968✔
611
{
612
   reg_t *r = vcode_reg_data(reg);
716,968✔
613

614
   vtype_kind_t kind = vtype_kind(r->type);
716,968✔
615
   if (kind != VCODE_TYPE_INT && kind != VCODE_TYPE_OFFSET)
716,968✔
616
      return false;
617

618
   vtype_t *bounds = vcode_type_data(r->bounds);
701,781✔
619

620
   VCODE_ASSERT(
701,781✔
621
      bounds->kind == VCODE_TYPE_INT || bounds->kind == VCODE_TYPE_OFFSET,
622
      "integer register r%d has non-integer bounds", reg);
623

624
   if (bounds->low == bounds->high) {
701,781✔
625
      if (value) *value = bounds->low;
439,403✔
626
      return true;
439,403✔
627
   }
628
   else
629
      return false;
630
}
631

632
void vcode_opt(void)
34,543✔
633
{
634
   // Prune assignments to unused registers
635

636
   int *uses LOCAL = xmalloc_array(active_unit->regs.count, sizeof(int));
69,086✔
637

638
   int pruned = 0;
34,543✔
639
   do {
53,821✔
640
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
53,821✔
641
      pruned = 0;
53,821✔
642

643
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
254,921✔
644
         block_t *b = &(active_unit->blocks.items[i]);
201,100✔
645

646
         for (int j = b->ops.count - 1; j >= 0; j--) {
2,779,020✔
647
            op_t *o = &(b->ops.items[j]);
2,577,920✔
648

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

708
            default:
709
               break;
710
            }
711

712
            for (int k = 0; k < o->args.count; k++) {
7,028,140✔
713
               if (o->args.items[k] != VCODE_INVALID_REG)
4,450,220✔
714
                  uses[o->args.items[k]]++;
4,404,850✔
715
            }
716
         }
717
      }
718
   } while (pruned > 0);
53,821✔
719

720
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
147,056✔
721
      block_t *b = &(active_unit->blocks.items[i]);
112,513✔
722
      op_t *dst = &(b->ops.items[0]);
112,513✔
723
      size_t copied = 0;
112,513✔
724
      for (int j = 0; j < b->ops.count; j++) {
1,487,590✔
725
         const op_t *src = &(b->ops.items[j]);
1,375,080✔
726
         if (src->kind != (vcode_op_t)-1) {
1,375,080✔
727
            if (src != dst) {
1,255,780✔
728
               assert(dst < src);
483,379✔
729
               *dst = *src;
483,379✔
730
            }
731
            dst++;
1,255,780✔
732
            copied++;
1,255,780✔
733
         }
734
      }
735

736
      assert(copied <= b->ops.count);
112,513✔
737
      b->ops.count = copied;
112,513✔
738
   }
739
}
34,543✔
740

741
void vcode_close(void)
17,799✔
742
{
743
   active_unit  = NULL;
17,799✔
744
   active_block = -1;
17,799✔
745
}
17,799✔
746

747
int vcode_count_blocks(void)
112,695✔
748
{
749
   assert(active_unit != NULL);
112,695✔
750
   return active_unit->blocks.count;
112,695✔
751
}
752

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

760
int vcode_count_vars(void)
80,218✔
761
{
762
   assert(active_unit != NULL);
80,218✔
763
   return active_unit->vars.count;
80,218✔
764
}
765

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

774
   return VCODE_INVALID_VAR;
775
}
776

777
ident_t vcode_var_name(vcode_var_t var)
44,245✔
778
{
779
   return vcode_var_data(var)->name;
44,245✔
780
}
781

782
vcode_type_t vcode_var_type(vcode_var_t var)
151,642✔
783
{
784
   return vcode_var_data(var)->type;
151,642✔
785
}
786

787
vcode_type_t vcode_var_bounds(vcode_var_t var)
2,618✔
788
{
789
   return vcode_var_data(var)->bounds;
2,618✔
790
}
791

792
vcode_var_flags_t vcode_var_flags(vcode_var_t var)
35,481✔
793
{
794
   return vcode_var_data(var)->flags;
35,481✔
795
}
796

797
vcode_op_t vcode_get_op(int op)
4,215,330✔
798
{
799
   return vcode_op_data(op)->kind;
4,215,330✔
800
}
801

802
ident_t vcode_get_func(int op)
108,033✔
803
{
804
   op_t *o = vcode_op_data(op);
108,033✔
805
   assert(OP_HAS_FUNC(o->kind));
108,033✔
806
   return o->func;
108,033✔
807
}
808

809
ident_t vcode_get_ident(int op)
91,590✔
810
{
811
   op_t *o = vcode_op_data(op);
91,590✔
812
   assert(OP_HAS_IDENT(o->kind));
91,590✔
813
   return o->ident;
91,590✔
814
}
815

816
unsigned vcode_get_subkind(int op)
80,785✔
817
{
818
   op_t *o = vcode_op_data(op);
80,785✔
819
   assert(OP_HAS_SUBKIND(o->kind));
80,785✔
820
   return o->subkind;
80,785✔
821
}
822

823
int64_t vcode_get_value(int op)
370,487✔
824
{
825
   op_t *o = vcode_op_data(op);
370,487✔
826
   assert(OP_HAS_VALUE(o->kind));
370,487✔
827
   return o->value;
370,487✔
828
}
829

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

837
vcode_var_t vcode_get_address(int op)
142,173✔
838
{
839
   op_t *o = vcode_op_data(op);
142,173✔
840
   assert(OP_HAS_ADDRESS(o->kind));
142,173✔
841
   return o->address;
142,173✔
842
}
843

844
unsigned vcode_get_dim(int op)
57,494✔
845
{
846
   op_t *o = vcode_op_data(op);
57,494✔
847
   assert(OP_HAS_DIM(o->kind));
57,494✔
848
   return o->dim;
57,494✔
849
}
850

851
int vcode_get_hops(int op)
50,929✔
852
{
853
   op_t *o = vcode_op_data(op);
50,929✔
854
   assert(OP_HAS_HOPS(o->kind));
50,929✔
855
   return o->hops;
50,929✔
856
}
857

858
int vcode_get_field(int op)
35,316✔
859
{
860
   op_t *o = vcode_op_data(op);
35,316✔
861
   assert(OP_HAS_FIELD(o->kind));
35,316✔
862
   return o->field;
35,316✔
863
}
864

865
vcode_var_t vcode_get_type(int op)
16,807✔
866
{
867
   op_t *o = vcode_op_data(op);
16,807✔
868
   assert(OP_HAS_TYPE(o->kind));
16,807✔
869
   return o->type;
16,807✔
870
}
871

872
int vcode_count_args(int op)
181,146✔
873
{
874
   return vcode_op_data(op)->args.count;
181,146✔
875
}
876

877
vcode_reg_t vcode_get_arg(int op, int arg)
3,412,270✔
878
{
879
   op_t *o = vcode_op_data(op);
3,412,270✔
880
   return vcode_reg_array_nth(&(o->args), arg);
3,412,270✔
881
}
882

883
vcode_reg_t vcode_get_result(int op)
1,044,720✔
884
{
885
   op_t *o = vcode_op_data(op);
1,044,720✔
886
   return o->result;
1,044,720✔
887
}
888

889
vcode_cmp_t vcode_get_cmp(int op)
28,976✔
890
{
891
   op_t *o = vcode_op_data(op);
28,976✔
892
   assert(OP_HAS_CMP(o->kind));
28,976✔
893
   return o->cmp;
28,976✔
894
}
895

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

903
const loc_t *vcode_get_loc(int op)
1,335,810✔
904
{
905
   op_t *o = vcode_op_data(op);
1,335,810✔
906
   return &(o->loc);
1,335,810✔
907
}
908

909
vcode_block_t vcode_get_target(int op, int nth)
123,943✔
910
{
911
   op_t *o = vcode_op_data(op);
123,943✔
912
   assert(OP_HAS_TARGET(o->kind));
123,943✔
913
   return vcode_block_array_nth(&(o->targets), nth);
123,943✔
914
}
915

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

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

924
bool vcode_block_finished(void)
1,468,760✔
925
{
926
   assert(active_unit != NULL);
1,468,760✔
927
   assert(active_block != VCODE_INVALID_BLOCK);
1,468,760✔
928

929
   const block_t *b = &(active_unit->blocks.items[active_block]);
1,468,760✔
930
   if (b->ops.count == 0)
1,468,760✔
931
      return false;
932
   else {
933
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,316,900✔
934
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,316,900✔
935
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,316,890✔
936
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
1,316,890✔
937
         || kind == VCODE_OP_UNREACHABLE;
3,939,950✔
938
   }
939
}
940

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

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

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

986
   return printed;
987
}
988

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

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

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

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

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

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

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

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

1070
   case VCODE_TYPE_OFFSET:
1071
      col += printf("#");
1072
      break;
1073

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

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

1084
   case VCODE_TYPE_OPAQUE:
1085
      col += printf("?");
1086
      break;
1087

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

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

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

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

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

1113
   return col;
1114
}
1115

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

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

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

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

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

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

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

1168
   dump_callback = callback;
1169
   dump_arg = arg;
1170

1171
   const vcode_unit_t vu = active_unit;
1172
   vcode_block_t old_block = active_block;
1173

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

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

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

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

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

1235
   if (vu->kind == VCODE_UNIT_FUNCTION
1236
       || vu->kind == VCODE_UNIT_PROCEDURE
1237
       || vu->kind == VCODE_UNIT_PROPERTY
1238
       || (vu->kind == VCODE_UNIT_THUNK && vu->params.count > 0)) {
1239

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1466
         case VCODE_OP_CLOSURE:
1467
         case VCODE_OP_PROTECTED_INIT:
1468
            {
1469
               col += vcode_dump_reg(op->result);
1470
               col += color_printf(" := %s $magenta$%s$$ context ",
1471
                                   vcode_op_string(op->kind), istr(op->func));
1472
               col += vcode_dump_reg(op->args.items[0]);
1473
               vcode_dump_result_type(col, op);
1474
            }
1475
            break;
1476

1477
         case VCODE_OP_PACKAGE_INIT:
1478
            {
1479
               col += vcode_dump_reg(op->result);
1480
               col += color_printf(" := %s $magenta$%s$$",
1481
                                   vcode_op_string(op->kind), istr(op->func));
1482
               if (op->args.count > 0) {
1483
                  col += printf(" context " );
1484
                  col += vcode_dump_reg(op->args.items[0]);
1485
               }
1486
               vcode_dump_result_type(col, op);
1487
            }
1488
            break;
1489

1490
         case VCODE_OP_PROCESS_INIT:
1491
            {
1492
               color_printf("%s $magenta$%s$$ locus ",
1493
                            vcode_op_string(op->kind), istr(op->func));
1494
               vcode_dump_reg(op->args.items[0]);
1495
            }
1496
            break;
1497

1498
         case VCODE_OP_PROTECTED_FREE:
1499
            {
1500
               printf("%s ", vcode_op_string(op->kind));
1501
               vcode_dump_reg(op->args.items[0]);
1502
            }
1503
            break;
1504

1505
         case VCODE_OP_WAIT:
1506
            {
1507
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1508
                            op->targets.items[0]);
1509
               if (op->args.items[0] != VCODE_INVALID_REG) {
1510
                  printf(" for ");
1511
                  vcode_dump_reg(op->args.items[0]);
1512
               }
1513
            }
1514
            break;
1515

1516
         case VCODE_OP_JUMP:
1517
            {
1518
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1519
                            op->targets.items[0]);
1520
            }
1521
            break;
1522

1523
         case VCODE_OP_COND:
1524
            {
1525
               printf("%s ", vcode_op_string(op->kind));
1526
               vcode_dump_reg(op->args.items[0]);
1527
               color_printf(" then $yellow$%d$$ else $yellow$%d$$",
1528
                            op->targets.items[0], op->targets.items[1]);
1529
            }
1530
            break;
1531

1532
         case VCODE_OP_ASSERT:
1533
            {
1534
               printf("%s ", vcode_op_string(op->kind));
1535
               vcode_dump_reg(op->args.items[0]);
1536
               if (op->args.items[2] != VCODE_INVALID_REG) {
1537
                  printf(" report ");
1538
                  vcode_dump_reg(op->args.items[2]);
1539
                  printf(" length ");
1540
                  vcode_dump_reg(op->args.items[3]);
1541
               }
1542
               printf(" severity ");
1543
               vcode_dump_reg(op->args.items[1]);
1544
               printf(" locus ");
1545
               vcode_dump_reg(op->args.items[4]);
1546
               if (op->args.count > 5) {
1547
                  printf(" hint ");
1548
                  vcode_dump_reg(op->args.items[5]);
1549
                  printf(" ");
1550
                  vcode_dump_reg(op->args.items[6]);
1551
               }
1552
            }
1553
            break;
1554

1555
         case VCODE_OP_REPORT:
1556
            {
1557
               printf("%s ", vcode_op_string(op->kind));
1558
               vcode_dump_reg(op->args.items[1]);
1559
               printf(" length ");
1560
               vcode_dump_reg(op->args.items[2]);
1561
               printf(" severity ");
1562
               vcode_dump_reg(op->args.items[0]);
1563
               printf(" locus ");
1564
               vcode_dump_reg(op->args.items[3]);
1565
            }
1566
            break;
1567

1568
         case VCODE_OP_LOAD:
1569
            {
1570
               col += vcode_dump_reg(op->result);
1571
               col += printf(" := %s ", vcode_op_string(op->kind));
1572
               col += vcode_dump_var(op->address, 0);
1573
               vcode_dump_result_type(col, op);
1574
            }
1575
            break;
1576

1577
         case VCODE_OP_LOAD_INDIRECT:
1578
            {
1579
               col += vcode_dump_reg(op->result);
1580
               col += color_printf(" := %s ", vcode_op_string(op->kind));
1581
               col += vcode_dump_reg(op->args.items[0]);
1582
               vcode_dump_result_type(col, op);
1583
            }
1584
            break;
1585

1586
         case VCODE_OP_STORE:
1587
            {
1588
               vcode_dump_var(op->address, 0);
1589
               printf(" := %s ", vcode_op_string(op->kind));
1590
               vcode_dump_reg(op->args.items[0]);
1591
            }
1592
            break;
1593

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

1602
         case VCODE_OP_INDEX:
1603
            {
1604
               col += vcode_dump_reg(op->result);
1605
               col += printf(" := %s ", vcode_op_string(op->kind));
1606
               col += vcode_dump_var(op->address, 0);
1607
               if (op->args.count > 0) {
1608
                  col += printf(" + ");
1609
                  col += vcode_dump_reg(op->args.items[0]);
1610
               }
1611
               vcode_dump_result_type(col, op);
1612
            }
1613
            break;
1614

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

1653
         case VCODE_OP_TRAP_ADD:
1654
         case VCODE_OP_TRAP_SUB:
1655
         case VCODE_OP_TRAP_MUL:
1656
         case VCODE_OP_TRAP_EXP:
1657
            {
1658
               col += vcode_dump_reg(op->result);
1659
               col += printf(" := %s ", vcode_op_string(op->kind));
1660
               col += vcode_dump_reg(op->args.items[0]);
1661
               switch (op->kind) {
1662
               case VCODE_OP_TRAP_ADD: col += printf(" + "); break;
1663
               case VCODE_OP_TRAP_SUB: col += printf(" - "); break;
1664
               case VCODE_OP_TRAP_MUL: col += printf(" * "); break;
1665
               case VCODE_OP_TRAP_EXP: col += printf(" ** "); break;
1666
               default: break;
1667
               }
1668
               col += vcode_dump_reg(op->args.items[1]);
1669
               col += printf(" locus ");
1670
               col += vcode_dump_reg(op->args.items[2]);
1671
               vcode_dump_result_type(col, op);
1672
            }
1673
            break;
1674

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

1684
         case VCODE_OP_COMMENT:
1685
            {
1686
               color_printf("$cyan$// %s$$ ", op->comment);
1687
            }
1688
            break;
1689

1690
         case VCODE_OP_CONST_ARRAY:
1691
         case VCODE_OP_CONST_RECORD:
1692
            {
1693
               col += vcode_dump_reg(op->result);
1694
               col += printf(" := const %c",
1695
                             op->kind == VCODE_OP_CONST_ARRAY ? '[' : '{');
1696
               for (int k = 0; k < op->args.count; k++) {
1697
                  if (k > 0)
1698
                     col += printf(",");
1699
                  col += vcode_dump_reg(op->args.items[k]);
1700
               }
1701

1702
               putchar(op->kind == VCODE_OP_CONST_ARRAY ? ']' : '}');
1703
               vcode_dump_result_type(col + 1, op);
1704
            }
1705
            break;
1706

1707
         case VCODE_OP_CONST_REP:
1708
            {
1709
               col += vcode_dump_reg(op->result);
1710
               col += printf(" := const [");
1711
               col += vcode_dump_reg(op->args.items[0]);
1712
               col += printf("]*%"PRIi64, op->value);
1713
               vcode_dump_result_type(col, op);
1714
            }
1715
            break;
1716

1717
         case VCODE_OP_ADDRESS_OF:
1718
         case VCODE_OP_CAST:
1719
            {
1720
               col += vcode_dump_reg(op->result);
1721
               col += printf(" := %s ", vcode_op_string(op->kind));
1722
               col += vcode_dump_reg(op->args.items[0]);
1723
               vcode_dump_result_type(col, op);
1724
            }
1725
            break;
1726

1727
         case VCODE_OP_RETURN:
1728
            {
1729
               printf("%s ", vcode_op_string(op->kind));
1730
               if (op->args.count > 0)
1731
                  vcode_dump_reg(op->args.items[0]);
1732
            }
1733
            break;
1734

1735
         case VCODE_OP_SCHED_WAVEFORM:
1736
            {
1737
               printf("%s ", vcode_op_string(op->kind));
1738
               vcode_dump_reg(op->args.items[0]);
1739
               printf(" count ");
1740
               vcode_dump_reg(op->args.items[1]);
1741
               printf(" values ");
1742
               vcode_dump_reg(op->args.items[2]);
1743
               printf(" reject ");
1744
               vcode_dump_reg(op->args.items[3]);
1745
               printf(" after ");
1746
               vcode_dump_reg(op->args.items[4]);
1747
            }
1748
            break;
1749

1750
         case VCODE_OP_FORCE:
1751
         case VCODE_OP_RELEASE:
1752
            {
1753
               printf("%s ", vcode_op_string(op->kind));
1754
               vcode_dump_reg(op->args.items[0]);
1755
               printf(" count ");
1756
               vcode_dump_reg(op->args.items[1]);
1757
               if (op->args.count > 2) {
1758
                  printf(" values ");
1759
                  vcode_dump_reg(op->args.items[2]);
1760
               }
1761
            }
1762
            break;
1763

1764
         case VCODE_OP_DISCONNECT:
1765
            {
1766
               printf("%s ", vcode_op_string(op->kind));
1767
               vcode_dump_reg(op->args.items[0]);
1768
               printf(" count ");
1769
               vcode_dump_reg(op->args.items[1]);
1770
               printf(" reject ");
1771
               vcode_dump_reg(op->args.items[2]);
1772
               printf(" after ");
1773
               vcode_dump_reg(op->args.items[3]);
1774
            }
1775
            break;
1776

1777
         case VCODE_OP_NEG:
1778
         case VCODE_OP_TRAP_NEG:
1779
         case VCODE_OP_ABS:
1780
         case VCODE_OP_RESOLVED:
1781
         case VCODE_OP_LAST_VALUE:
1782
            {
1783
               col += vcode_dump_reg(op->result);
1784
               col += printf(" := %s ", vcode_op_string(op->kind));
1785
               col += vcode_dump_reg(op->args.items[0]);
1786
               if (op->args.count > 1) {
1787
                  col += printf(" locus ");
1788
                  col += vcode_dump_reg(op->args.items[1]);
1789
               }
1790
               vcode_dump_result_type(col, op);
1791
            }
1792
            break;
1793

1794
         case VCODE_OP_SELECT:
1795
            {
1796
               col += vcode_dump_reg(op->result);
1797
               col += printf(" := %s ", vcode_op_string(op->kind));
1798
               col += vcode_dump_reg(op->args.items[0]);
1799
               col += printf(" then ");
1800
               col += vcode_dump_reg(op->args.items[1]);
1801
               col += printf(" else ");
1802
               col += vcode_dump_reg(op->args.items[2]);
1803
               vcode_dump_result_type(col, op);
1804
            }
1805
            break;
1806

1807
         case VCODE_OP_WRAP:
1808
            {
1809
               col += vcode_dump_reg(op->result);
1810
               col += printf(" := %s ", vcode_op_string(op->kind));
1811
               col += vcode_dump_reg(op->args.items[0]);
1812
               col += printf(" [");
1813
               for (int i = 1; i < op->args.count; i += 3) {
1814
                  if (i > 1)
1815
                     col += printf(", ");
1816
                  col += vcode_dump_reg(op->args.items[i + 0]);
1817
                  col += printf(" ");
1818
                  col += vcode_dump_reg(op->args.items[i + 1]);
1819
                  col += printf(" ");
1820
                  col += vcode_dump_reg(op->args.items[i + 2]);
1821
               }
1822
               col += printf("]");
1823
               vcode_dump_result_type(col, op);
1824
            }
1825
            break;
1826

1827
         case VCODE_OP_UARRAY_LEFT:
1828
         case VCODE_OP_UARRAY_RIGHT:
1829
         case VCODE_OP_UARRAY_DIR:
1830
         case VCODE_OP_UARRAY_LEN:
1831
            {
1832
               col += vcode_dump_reg(op->result);
1833
               col += printf(" := %s ", vcode_op_string(op->kind));
1834
               col += vcode_dump_reg(op->args.items[0]);
1835
               col += printf(" dim %d", op->dim);
1836
               vcode_dump_result_type(col, op);
1837
            }
1838
            break;
1839

1840
         case VCODE_OP_UNWRAP:
1841
            {
1842
               col += vcode_dump_reg(op->result);
1843
               col += printf(" := %s ", vcode_op_string(op->kind));
1844
               col += vcode_dump_reg(op->args.items[0]);
1845
               vcode_dump_result_type(col, op);
1846
            }
1847
            break;
1848

1849
         case VCODE_OP_VAR_UPREF:
1850
            {
1851
               col += vcode_dump_reg(op->result);
1852
               col += printf(" := %s %d, ", vcode_op_string(op->kind),
1853
                             op->hops);
1854
               col += vcode_dump_var(op->address, op->hops);
1855
               vcode_dump_result_type(col, op);
1856
            }
1857
            break;
1858

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

1867
         case VCODE_OP_ACTIVE:
1868
         case VCODE_OP_EVENT:
1869
         case VCODE_OP_DRIVING:
1870
            {
1871
               col += vcode_dump_reg(op->result);
1872
               col += printf(" := %s ", vcode_op_string(op->kind));
1873
               col += vcode_dump_reg(op->args.items[0]);
1874
               col += printf(" length ");
1875
               col += vcode_dump_reg(op->args.items[1]);
1876
               vcode_dump_result_type(col, op);
1877
            }
1878
            break;
1879

1880
         case VCODE_OP_RECORD_REF:
1881
            {
1882
               col += vcode_dump_reg(op->result);
1883
               col += printf(" := %s ", vcode_op_string(op->kind));
1884
               col += vcode_dump_reg(op->args.items[0]);
1885
               col += printf(" field %d", op->field);
1886
               vcode_dump_result_type(col, op);
1887
            }
1888
            break;
1889

1890
         case VCODE_OP_ARRAY_REF:
1891
            {
1892
               col += vcode_dump_reg(op->result);
1893
               col += printf(" := %s ", vcode_op_string(op->kind));
1894
               col += vcode_dump_reg(op->args.items[0]);
1895
               col += printf(" offset ");
1896
               col += vcode_dump_reg(op->args.items[1]);
1897
               vcode_dump_result_type(col, op);
1898
            }
1899
            break;
1900

1901
         case VCODE_OP_COPY:
1902
            {
1903
               vcode_dump_reg(op->args.items[0]);
1904
               printf(" := %s ", vcode_op_string(op->kind));
1905
               vcode_dump_reg(op->args.items[1]);
1906
               if (op->args.count > 2) {
1907
                  printf(" count " );
1908
                  vcode_dump_reg(op->args.items[2]);
1909
               }
1910
            }
1911
            break;
1912

1913
         case VCODE_OP_SCHED_EVENT:
1914
         case VCODE_OP_CLEAR_EVENT:
1915
            {
1916
               printf("%s on ", vcode_op_string(op->kind));
1917
               vcode_dump_reg(op->args.items[0]);
1918
               printf(" count ");
1919
               vcode_dump_reg(op->args.items[1]);
1920
            }
1921
            break;
1922

1923
         case VCODE_OP_IMPLICIT_EVENT:
1924
            {
1925
               printf("%s on ", vcode_op_string(op->kind));
1926
               vcode_dump_reg(op->args.items[0]);
1927
               printf(" count ");
1928
               vcode_dump_reg(op->args.items[1]);
1929
               printf(" wake ");
1930
               vcode_dump_reg(op->args.items[2]);
1931
            }
1932
            break;
1933

1934
         case VCODE_OP_PCALL:
1935
            {
1936
               color_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
1937
                            istr(op->func));
1938
               for (int i = 0; i < op->args.count; i++) {
1939
                  printf("%s", i > 0 ? ", " : " ");
1940
                  vcode_dump_reg(op->args.items[i]);
1941
               }
1942
               if (op->targets.count > 0)
1943
                  color_printf(" resume $yellow$%d$$", op->targets.items[0]);
1944
            }
1945
            break;
1946

1947
         case VCODE_OP_RESUME:
1948
            {
1949
               color_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
1950
                            istr(op->func));
1951
            }
1952
            break;
1953

1954
         case VCODE_OP_MEMSET:
1955
            {
1956
               vcode_dump_reg(op->args.items[0]);
1957
               printf(" := %s ", vcode_op_string(op->kind));
1958
               vcode_dump_reg(op->args.items[1]);
1959
               printf(" length ");
1960
               vcode_dump_reg(op->args.items[2]);
1961
            }
1962
            break;
1963

1964
         case VCODE_OP_CASE:
1965
            {
1966
               printf("%s ", vcode_op_string(op->kind));
1967
               vcode_dump_reg(op->args.items[0]);
1968
               color_printf(" default $yellow$%d$$", op->targets.items[0]);
1969
               for (int i = 1; i < op->args.count; i++) {
1970
                  printf(" [");
1971
                  vcode_dump_reg(op->args.items[i]);
1972
                  color_printf(" $yellow$%d$$]", op->targets.items[i]);
1973
               }
1974
            }
1975
            break;
1976

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

1986
         case VCODE_OP_FILE_OPEN:
1987
            {
1988
               printf("%s ", vcode_op_string(op->kind));
1989
               vcode_dump_reg(op->args.items[0]);
1990
               printf(" name ");
1991
               vcode_dump_reg(op->args.items[1]);
1992
               printf(" length ");
1993
               vcode_dump_reg(op->args.items[2]);
1994
               printf(" kind ");
1995
               vcode_dump_reg(op->args.items[3]);
1996
               if (op->args.count == 5) {
1997
                  printf(" status ");
1998
                  vcode_dump_reg(op->args.items[4]);
1999
               }
2000
            }
2001
            break;
2002

2003
         case VCODE_OP_FILE_CLOSE:
2004
            {
2005
               printf("%s ", vcode_op_string(op->kind));
2006
               vcode_dump_reg(op->args.items[0]);
2007
            }
2008
            break;
2009

2010
         case VCODE_OP_FILE_WRITE:
2011
            {
2012
               printf("%s ", vcode_op_string(op->kind));
2013
               vcode_dump_reg(op->args.items[0]);
2014
               printf(" value ");
2015
               vcode_dump_reg(op->args.items[1]);
2016
               if (op->args.count == 3) {
2017
                  printf(" length ");
2018
                  vcode_dump_reg(op->args.items[2]);
2019
               }
2020
            }
2021
            break;
2022

2023
         case VCODE_OP_FILE_READ:
2024
            {
2025
               printf("%s ", vcode_op_string(op->kind));
2026
               vcode_dump_reg(op->args.items[0]);
2027
               printf(" ptr ");
2028
               vcode_dump_reg(op->args.items[1]);
2029
               if (op->args.count >= 3) {
2030
                  printf(" inlen ");
2031
                  vcode_dump_reg(op->args.items[2]);
2032
                  if (op->args.count >= 4) {
2033
                     printf(" outlen ");
2034
                     vcode_dump_reg(op->args.items[3]);
2035
                  }
2036
               }
2037
            }
2038
            break;
2039

2040
         case VCODE_OP_NULL:
2041
         case VCODE_OP_NEW:
2042
            {
2043
               col += vcode_dump_reg(op->result);
2044
               col += printf(" := %s", vcode_op_string(op->kind));
2045
               if (op->args.count == 1) {
2046
                  col += printf(" length ");
2047
                  col += vcode_dump_reg(op->args.items[0]);
2048
               }
2049
               vcode_dump_result_type(col, op);
2050
            }
2051
            break;
2052

2053
         case VCODE_OP_NULL_CHECK:
2054
            {
2055
               col += printf("%s ", vcode_op_string(op->kind));
2056
               col += vcode_dump_reg(op->args.items[0]);
2057
               col += printf(" locus ");
2058
               col += vcode_dump_reg(op->args.items[1]);
2059
            }
2060
            break;
2061

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

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

2078
         case VCODE_OP_LAST_EVENT:
2079
         case VCODE_OP_LAST_ACTIVE:
2080
         case VCODE_OP_DRIVING_VALUE:
2081
            {
2082
               col += vcode_dump_reg(op->result);
2083
               col += printf(" := %s ", vcode_op_string(op->kind));
2084
               col += vcode_dump_reg(op->args.items[0]);
2085
               if (op->args.count > 1) {
2086
                  col += printf(" length ");
2087
                  col += vcode_dump_reg(op->args.items[1]);
2088
               }
2089
               vcode_dump_result_type(col, op);
2090
            }
2091
            break;
2092

2093
         case VCODE_OP_ALIAS_SIGNAL:
2094
            {
2095
               printf("%s ", vcode_op_string(op->kind));
2096
               vcode_dump_reg(op->args.items[0]);
2097
               printf(" locus ");
2098
               vcode_dump_reg(op->args.items[1]);
2099
            }
2100
            break;
2101

2102
         case VCODE_OP_LENGTH_CHECK:
2103
            {
2104
               col += printf("%s left ", vcode_op_string(op->kind));
2105
               col += vcode_dump_reg(op->args.items[0]);
2106
               col += printf(" == right ");
2107
               col += vcode_dump_reg(op->args.items[1]);
2108
               col += printf(" locus ");
2109
               col += vcode_dump_reg(op->args.items[2]);
2110
               if (op->args.count > 3) {
2111
                  col += printf(" dim ");
2112
                  col += vcode_dump_reg(op->args.items[3]);
2113
               }
2114
            }
2115
            break;
2116

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

2127
         case VCODE_OP_INDEX_CHECK:
2128
         case VCODE_OP_RANGE_CHECK:
2129
            {
2130
               col += printf("%s ", vcode_op_string(op->kind));
2131
               col += vcode_dump_reg(op->args.items[0]);
2132
               col += printf(" left ");
2133
               col += vcode_dump_reg(op->args.items[1]);
2134
               col += printf(" right ");
2135
               col += vcode_dump_reg(op->args.items[2]);
2136
               col += printf(" dir ");
2137
               col += vcode_dump_reg(op->args.items[3]);
2138
               col += printf(" locus ");
2139
               col += vcode_dump_reg(op->args.items[4]);
2140
               if (op->args.items[5] != op->args.items[4]) {
2141
                  col += printf(" hint ");
2142
                  col += vcode_dump_reg(op->args.items[5]);
2143
               }
2144
            }
2145
            break;
2146

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

2154
         case VCODE_OP_COVER_STMT:
2155
            {
2156
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2157
            }
2158
            break;
2159

2160
         case VCODE_OP_COVER_TOGGLE:
2161
         case VCODE_OP_COVER_BRANCH:
2162
         case VCODE_OP_COVER_EXPR:
2163
            {
2164
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2165
               vcode_dump_reg(op->args.items[0]);
2166
            }
2167
            break;
2168

2169
         case VCODE_OP_UNDEFINED:
2170
            {
2171
               col += vcode_dump_reg(op->result);
2172
               col += printf(" := %s", vcode_op_string(op->kind));
2173
               vcode_dump_result_type(col, op);
2174
            }
2175
            break;
2176

2177
         case VCODE_OP_RANGE_LENGTH:
2178
         case VCODE_OP_RANGE_NULL:
2179
            {
2180
               col += vcode_dump_reg(op->result);
2181
               col += printf(" := %s left ", vcode_op_string(op->kind));
2182
               vcode_dump_reg(op->args.items[0]);
2183
               col += printf(" right ");
2184
               vcode_dump_reg(op->args.items[1]);
2185
               col += printf(" dir ");
2186
               col += vcode_dump_reg(op->args.items[2]);
2187
               vcode_dump_result_type(col, op);
2188
            }
2189
            break;
2190

2191
         case VCODE_OP_LINK_PACKAGE:
2192
         case VCODE_OP_LINK_INSTANCE:
2193
            {
2194
               col += vcode_dump_reg(op->result);
2195
               col += color_printf(" := %s $magenta$%s$$",
2196
                                   vcode_op_string(op->kind), istr(op->ident));
2197
               if (op->args.count > 0) {
2198
                  col += printf(" locus ");
2199
                  col += vcode_dump_reg(op->args.items[0]);
2200
               }
2201
               vcode_dump_result_type(col, op);
2202
            }
2203
            break;
2204

2205
         case VCODE_OP_LINK_VAR:
2206
            {
2207
               col += vcode_dump_reg(op->result);
2208
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2209
               col += vcode_dump_reg(op->args.items[0]);
2210
               col += color_printf(" $magenta$%s$$", istr(op->ident));
2211
               vcode_dump_result_type(col, op);
2212
            }
2213
            break;
2214

2215
         case VCODE_OP_UNREACHABLE:
2216
            {
2217
               printf("%s", vcode_op_string(op->kind));
2218
               if (op->args.count > 0) {
2219
                  printf(" ");
2220
                  vcode_dump_reg(op->args.items[0]);
2221
               }
2222
            }
2223
            break;
2224

2225
         case VCODE_OP_DEBUG_LOCUS:
2226
            {
2227
               col += vcode_dump_reg(op->result);
2228
               col += color_printf(" := %s $magenta$%s$$%+"PRIi64,
2229
                                   vcode_op_string(op->kind),
2230
                                   istr(op->ident), op->value);
2231
               vcode_dump_result_type(col, op);
2232
            }
2233
            break;
2234

2235
         case VCODE_OP_ENTER_STATE:
2236
            {
2237
               printf("%s ", vcode_op_string(op->kind));
2238
               vcode_dump_reg(op->args.items[0]);
2239
            }
2240
            break;
2241

2242
         case VCODE_OP_REFLECT_VALUE:
2243
            {
2244
               col += vcode_dump_reg(op->result);
2245
               col += printf(" := %s ", vcode_op_string(op->kind));
2246
               vcode_dump_reg(op->args.items[0]);
2247
               col += printf(" context ");
2248
               vcode_dump_reg(op->args.items[1]);
2249
               col += printf(" locus ");
2250
               col += vcode_dump_reg(op->args.items[2]);
2251
               if (op->args.count > 3) {
2252
                  col += printf(" bounds ");
2253
                  col += vcode_dump_reg(op->args.items[3]);
2254
               }
2255
               vcode_dump_result_type(col, op);
2256
            }
2257
            break;
2258

2259
         case VCODE_OP_REFLECT_SUBTYPE:
2260
            {
2261
               col += vcode_dump_reg(op->result);
2262
               col += printf(" := %s ", vcode_op_string(op->kind));
2263
               col += printf(" context ");
2264
               vcode_dump_reg(op->args.items[0]);
2265
               col += printf(" locus ");
2266
               col += vcode_dump_reg(op->args.items[1]);
2267
               if (op->args.count > 2) {
2268
                  col += printf(" bounds ");
2269
                  col += vcode_dump_reg(op->args.items[2]);
2270
               }
2271
               vcode_dump_result_type(col, op);
2272
            }
2273
            break;
2274

2275
         case VCODE_OP_FUNCTION_TRIGGER:
2276
            {
2277
               col += vcode_dump_reg(op->result);
2278
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2279
               col += vcode_dump_reg(op->args.items[0]);
2280
               vcode_dump_result_type(col, op);
2281
            }
2282
            break;
2283

2284
         case VCODE_OP_ADD_TRIGGER:
2285
            {
2286
               printf("%s ", vcode_op_string(op->kind));
2287
               vcode_dump_reg(op->args.items[0]);
2288
            }
2289
            break;
2290
         }
2291

2292
         if (j == mark_op && i == old_block)
2293
            color_printf("\t $red$<----$$");
2294

2295
         color_printf("$$\n");
2296

2297
         if (callback != NULL)
2298
            (*callback)(VCODE_DUMP_OP, j, arg);
2299
      }
2300

2301
      if (b->ops.count == 0)
2302
         color_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2303
   }
2304

2305
   printf("\n");
2306
   fflush(stdout);
2307

2308
   active_block = old_block;
2309
}
2310
LCOV_EXCL_STOP
2311

2312
bool vtype_eq(vcode_type_t a, vcode_type_t b)
28,159,500✔
2313
{
2314
   assert(active_unit != NULL);
28,567,600✔
2315

2316
   if (a == b)
28,567,600✔
2317
      return true;
2318
   else {
2319
      const vtype_t *at = vcode_type_data(a);
26,237,200✔
2320
      const vtype_t *bt = vcode_type_data(b);
26,237,200✔
2321

2322
      if (at->kind != bt->kind)
26,237,200✔
2323
         return false;
2324

2325
      switch (at->kind) {
11,910,000✔
2326
      case VCODE_TYPE_INT:
10,131,300✔
2327
         return (at->low == bt->low) && (at->high == bt->high);
19,083,900✔
2328
      case VCODE_TYPE_REAL:
910,233✔
2329
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
1,772,270✔
2330
      case VCODE_TYPE_CARRAY:
73,023✔
2331
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
79,156✔
2332
      case VCODE_TYPE_UARRAY:
68,964✔
2333
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
83,737✔
2334
      case VCODE_TYPE_POINTER:
344,307✔
2335
      case VCODE_TYPE_ACCESS:
2336
         return vtype_eq(at->pointed, bt->pointed);
344,307✔
2337
      case VCODE_TYPE_OFFSET:
2338
      case VCODE_TYPE_OPAQUE:
2339
      case VCODE_TYPE_DEBUG_LOCUS:
2340
      case VCODE_TYPE_TRIGGER:
2341
         return true;
2342
      case VCODE_TYPE_RESOLUTION:
63,732✔
2343
      case VCODE_TYPE_CLOSURE:
2344
      case VCODE_TYPE_SIGNAL:
2345
      case VCODE_TYPE_FILE:
2346
         return vtype_eq(at->base, bt->base);
63,732✔
2347
      case VCODE_TYPE_RECORD:
55,363✔
2348
      case VCODE_TYPE_CONTEXT:
2349
         return at->name == bt->name;
55,363✔
2350
      }
2351

2352
      return false;
×
2353
   }
2354
}
2355

2356
void vcode_dump(void)
×
2357
{
2358
   vcode_dump_with_mark(-1, NULL, NULL);
×
2359
}
×
2360

2361
static vcode_type_t vtype_new(vtype_t *new)
2362
{
2363
   int index = active_unit->types.count - 1;
2364
   vcode_type_t type = MAKE_HANDLE(active_unit->depth, index);
2365

2366
   for (int i = 0; i < index; i++) {
2367
      vcode_type_t this = MAKE_HANDLE(active_unit->depth, i);
2368
      if (vtype_eq(this, type)) {
2369
         active_unit->types.count--;
2370
         return this;
2371
      }
2372
   }
2373

2374
   return type;
2375
}
2376

2377
vcode_type_t vtype_int(int64_t low, int64_t high)
1,425,980✔
2378
{
2379
   assert(active_unit != NULL);
1,425,980✔
2380

2381
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,425,980✔
2382
   n->kind = VCODE_TYPE_INT;
1,425,980✔
2383
   n->low  = low;
1,425,980✔
2384
   n->high = high;
1,425,980✔
2385

2386
   switch (bits_for_range(low, high)) {
1,425,980✔
2387
   case 64:
111,277✔
2388
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
111,277✔
2389
      break;
111,277✔
2390
   case 32:
337,414✔
2391
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
337,414✔
2392
      break;
337,414✔
2393
   case 16:
2,440✔
2394
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
2,440✔
2395
      break;
2,440✔
2396
   case 8:
398,738✔
2397
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
398,738✔
2398
      break;
398,738✔
2399
   case 1:
576,110✔
2400
      n->repr = VCODE_REPR_U1;
576,110✔
2401
      break;
576,110✔
2402
   default:
×
2403
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
×
2404
   }
2405

2406
   return vtype_new(n);
1,425,980✔
2407
}
2408

2409
vcode_type_t vtype_bool(void)
287,796✔
2410
{
2411
   return vtype_int(0, 1);
287,796✔
2412
}
2413

2414
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
33,259✔
2415
{
2416
   assert(active_unit != NULL);
33,259✔
2417

2418
   const vtype_kind_t ekind = vtype_kind(elem);
33,259✔
2419
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
33,259✔
2420
                "array types may not be nested");
2421

2422
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
33,259✔
2423
   memset(n, '\0', sizeof(vtype_t));
33,259✔
2424
   n->kind   = VCODE_TYPE_CARRAY;
33,259✔
2425
   n->elem   = elem;
33,259✔
2426
   n->bounds = bounds;
33,259✔
2427
   n->size   = MAX(size, 0);
33,259✔
2428

2429
   return vtype_new(n);
33,259✔
2430
}
2431

2432
vcode_type_t vtype_find_named_record(ident_t name)
24,476✔
2433
{
2434
   assert(active_unit != NULL);
24,476✔
2435

2436
   for (int i = 0; i < active_unit->types.count; i++) {
341,720✔
2437
      vtype_t *other = &(active_unit->types.items[i]);
333,358✔
2438
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
333,358✔
2439
         return MAKE_HANDLE(active_unit->depth, i);
16,114✔
2440
   }
2441

2442
   return VCODE_INVALID_TYPE;
2443
}
2444

2445
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
8,362✔
2446
                                int nfields)
2447
{
2448
   assert(active_unit != NULL);
8,362✔
2449

2450
   vtype_t *data = NULL;
8,362✔
2451
   vcode_type_t handle = vtype_find_named_record(name);
8,362✔
2452
   if (handle == VCODE_INVALID_TYPE) {
8,362✔
2453
      data = vtype_array_alloc(&(active_unit->types));
4,189✔
2454
      memset(data, '\0', sizeof(vtype_t));
4,189✔
2455
      data->kind = VCODE_TYPE_RECORD;
4,189✔
2456
      data->name = name;
4,189✔
2457

2458
      handle = vtype_new(data);
4,189✔
2459
   }
2460
   else {
2461
      data = vcode_type_data(handle);
4,173✔
2462
      VCODE_ASSERT(data->fields.count == 0,
4,173✔
2463
                    "record type %s already defined", istr(name));
2464
   }
2465

2466
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
8,362✔
2467
   for (int i = 0; i < nfields; i++)
23,355✔
2468
      vcode_type_array_add(&(data->fields), field_types[i]);
14,993✔
2469

2470
   return handle;
8,362✔
2471
}
2472

2473
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
68,152✔
2474
{
2475
   assert(active_unit != NULL);
68,152✔
2476

2477
   const vtype_kind_t ekind = vtype_kind(elem);
68,152✔
2478
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
68,152✔
2479
                "array types may not be nested");
2480

2481
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
68,152✔
2482

2483
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
68,152✔
2484
   memset(n, '\0', sizeof(vtype_t));
68,152✔
2485
   n->kind   = VCODE_TYPE_UARRAY;
68,152✔
2486
   n->elem   = elem;
68,152✔
2487
   n->bounds = bounds;
68,152✔
2488
   n->dims   = ndim;
68,152✔
2489

2490
   return vtype_new(n);
68,152✔
2491
}
2492

2493
vcode_type_t vtype_pointer(vcode_type_t to)
142,253✔
2494
{
2495
   assert(active_unit != NULL);
142,253✔
2496

2497
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
142,253✔
2498
   n->kind    = VCODE_TYPE_POINTER;
142,253✔
2499
   n->pointed = to;
142,253✔
2500

2501
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
142,253✔
2502
                "cannot get pointer to carray type");
2503

2504
   return vtype_new(n);
142,253✔
2505
}
2506

2507
vcode_type_t vtype_access(vcode_type_t to)
4,368✔
2508
{
2509
   assert(active_unit != NULL);
4,368✔
2510

2511
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
4,368✔
2512
   n->kind    = VCODE_TYPE_ACCESS;
4,368✔
2513
   n->pointed = to;
4,368✔
2514

2515
   return vtype_new(n);
4,368✔
2516
}
2517

2518
vcode_type_t vtype_signal(vcode_type_t base)
24,896✔
2519
{
2520
   assert(active_unit != NULL);
24,896✔
2521

2522
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
24,896✔
2523
   n->kind = VCODE_TYPE_SIGNAL;
24,896✔
2524
   n->base = base;
24,896✔
2525

2526
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
24,896✔
2527

2528
   return vtype_new(n);
24,896✔
2529
}
2530

2531
vcode_type_t vtype_resolution(vcode_type_t base)
563✔
2532
{
2533
   assert(active_unit != NULL);
563✔
2534

2535
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
563✔
2536
   n->kind = VCODE_TYPE_RESOLUTION;
563✔
2537
   n->base = base;
563✔
2538

2539
   return vtype_new(n);
563✔
2540
}
2541

2542
vcode_type_t vtype_closure(vcode_type_t result)
695✔
2543
{
2544
   assert(active_unit != NULL);
695✔
2545

2546
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
695✔
2547
   n->kind = VCODE_TYPE_CLOSURE;
695✔
2548
   n->base = result;
695✔
2549

2550
   return vtype_new(n);
695✔
2551
}
2552

2553
vcode_type_t vtype_context(ident_t name)
42,525✔
2554
{
2555
   assert(active_unit != NULL);
42,525✔
2556
   assert(name != NULL);
42,525✔
2557

2558
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
42,525✔
2559
   n->kind = VCODE_TYPE_CONTEXT;
42,525✔
2560
   n->name = name;
42,525✔
2561

2562
   return vtype_new(n);
42,525✔
2563
}
2564

2565
vcode_type_t vtype_file(vcode_type_t base)
346✔
2566
{
2567
   assert(active_unit != NULL);
346✔
2568

2569
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
346✔
2570
   n->kind = VCODE_TYPE_FILE;
346✔
2571
   n->base = base;
346✔
2572

2573
   return vtype_new(n);
346✔
2574
}
2575

2576
vcode_type_t vtype_offset(void)
216,223✔
2577
{
2578
   assert(active_unit != NULL);
216,223✔
2579

2580
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
216,223✔
2581
   n->kind = VCODE_TYPE_OFFSET;
216,223✔
2582
   n->low  = INT64_MIN;
216,223✔
2583
   n->high = INT64_MAX;
216,223✔
2584
   n->repr = VCODE_REPR_I64;
216,223✔
2585

2586
   return vtype_new(n);
216,223✔
2587
}
2588

2589
vcode_type_t vtype_time(void)
13,760✔
2590
{
2591
   return vtype_int(INT64_MIN, INT64_MAX);
13,760✔
2592
}
2593

2594
vcode_type_t vtype_char(void)
7,309✔
2595
{
2596
   return vtype_int(0, 255);
7,309✔
2597
}
2598

2599
vcode_type_t vtype_opaque(void)
295✔
2600
{
2601
   assert(active_unit != NULL);
295✔
2602

2603
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
295✔
2604
   n->kind = VCODE_TYPE_OPAQUE;
295✔
2605

2606
   return vtype_new(n);
295✔
2607
}
2608

2609
vcode_type_t vtype_debug_locus(void)
79,860✔
2610
{
2611
   assert(active_unit != NULL);
79,860✔
2612

2613
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
79,860✔
2614
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
79,860✔
2615

2616
   return vtype_new(n);
79,860✔
2617
}
2618

2619
vcode_type_t vtype_trigger(void)
24✔
2620
{
2621
   assert(active_unit != NULL);
24✔
2622

2623
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
24✔
2624
   n->kind = VCODE_TYPE_TRIGGER;
24✔
2625

2626
   return vtype_new(n);
24✔
2627
}
2628

2629
vcode_type_t vtype_real(double low, double high)
75,041✔
2630
{
2631
   assert(active_unit != NULL);
75,041✔
2632

2633
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
75,041✔
2634
   n->kind  = VCODE_TYPE_REAL;
75,041✔
2635
   n->rlow  = low;
75,041✔
2636
   n->rhigh = high;
75,041✔
2637

2638
   return vtype_new(n);
75,041✔
2639
}
2640

2641
vtype_kind_t vtype_kind(vcode_type_t type)
5,318,910✔
2642
{
2643
   vtype_t *vt = vcode_type_data(type);
5,318,910✔
2644
   return vt->kind;
5,318,910✔
2645
}
2646

2647
vtype_repr_t vtype_repr(vcode_type_t type)
489,036✔
2648
{
2649
   vtype_t *vt = vcode_type_data(type);
489,036✔
2650
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
489,036✔
2651
   return vt->repr;
489,036✔
2652
}
2653

2654
vcode_type_t vtype_elem(vcode_type_t type)
354,178✔
2655
{
2656
   vtype_t *vt = vcode_type_data(type);
354,178✔
2657
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
354,178✔
2658
   return vt->elem;
354,178✔
2659
}
2660

2661
vcode_type_t vtype_base(vcode_type_t type)
11,816✔
2662
{
2663
   vtype_t *vt = vcode_type_data(type);
11,816✔
2664
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
11,816✔
2665
          || vt->kind == VCODE_TYPE_RESOLUTION
2666
          || vt->kind == VCODE_TYPE_CLOSURE);
2667
   return vt->base;
11,816✔
2668
}
2669

2670
vcode_type_t vtype_bounds(vcode_type_t type)
10,840✔
2671
{
2672
   vtype_t *vt = vcode_type_data(type);
10,840✔
2673
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
10,840✔
2674
   return vt->bounds;
10,840✔
2675
}
2676

2677
unsigned vtype_dims(vcode_type_t type)
118,359✔
2678
{
2679
   vtype_t *vt = vcode_type_data(type);
118,359✔
2680
   assert(vt->kind == VCODE_TYPE_UARRAY);
118,359✔
2681
   return vt->dims;
118,359✔
2682
}
2683

2684
unsigned vtype_size(vcode_type_t type)
88,837✔
2685
{
2686
   vtype_t *vt = vcode_type_data(type);
88,837✔
2687
   assert(vt->kind == VCODE_TYPE_CARRAY);
88,837✔
2688
   return vt->size;
88,837✔
2689
}
2690

2691
int vtype_fields(vcode_type_t type)
23,836✔
2692
{
2693
   vtype_t *vt = vcode_type_data(type);
23,836✔
2694
   assert(vt->kind == VCODE_TYPE_RECORD);
23,836✔
2695
   return vt->fields.count;
23,836✔
2696
}
2697

2698
vcode_type_t vtype_field(vcode_type_t type, int field)
236,609✔
2699
{
2700
   vtype_t *vt = vcode_type_data(type);
236,609✔
2701
   assert(vt->kind == VCODE_TYPE_RECORD);
236,609✔
2702
   return vcode_type_array_nth(&(vt->fields), field);
236,609✔
2703
}
2704

2705
ident_t vtype_name(vcode_type_t type)
3,435✔
2706
{
2707
   vtype_t *vt = vcode_type_data(type);
3,435✔
2708
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
3,435✔
2709
   return vt->name;
3,435✔
2710
}
2711

2712
vcode_type_t vtype_pointed(vcode_type_t type)
282,147✔
2713
{
2714
   vtype_t *vt = vcode_type_data(type);
282,147✔
2715
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
282,147✔
2716
   return vt->pointed;
282,147✔
2717
}
2718

2719
int64_t vtype_low(vcode_type_t type)
98✔
2720
{
2721
   vtype_t *vt = vcode_type_data(type);
98✔
2722
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
98✔
2723
   return vt->low;
98✔
2724
}
2725

2726
int64_t vtype_high(vcode_type_t type)
541✔
2727
{
2728
   vtype_t *vt = vcode_type_data(type);
541✔
2729
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
541✔
2730
   return vt->high;
541✔
2731
}
2732

2733
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
531✔
2734
{
2735
   return vtype_kind(type) == VCODE_TYPE_POINTER
531✔
2736
      && vtype_kind(vtype_pointed(type)) == to;
531✔
2737
}
2738

2739
bool vtype_is_scalar(vcode_type_t type)
275,745✔
2740
{
2741
   const vtype_kind_t kind = vtype_kind(type);
275,745✔
2742
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
275,745✔
2743
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
80,628✔
2744
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
59,936✔
2745
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
56,922✔
2746
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER;
277,115✔
2747
}
2748

2749
bool vtype_is_composite(vcode_type_t type)
21,972✔
2750
{
2751
   const vtype_kind_t kind = vtype_kind(type);
21,972✔
2752
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
21,972✔
2753
}
2754

2755
bool vtype_is_signal(vcode_type_t type)
142,448✔
2756
{
2757
   vtype_t *vt = vcode_type_data(type);
255,250✔
2758
   switch (vt->kind) {
255,250✔
2759
   case VCODE_TYPE_SIGNAL:
2760
      return true;
2761
   case VCODE_TYPE_POINTER:
59,595✔
2762
      return vtype_is_signal(vt->pointed);
59,595✔
2763
   case VCODE_TYPE_RECORD:
2764
      for (int i = 0; i < vt->fields.count; i++) {
28,961✔
2765
         if (vtype_is_signal(vt->fields.items[i]))
23,294✔
2766
            return true;
2767
      }
2768
      return false;
2769
   case VCODE_TYPE_UARRAY:
53,207✔
2770
   case VCODE_TYPE_CARRAY:
2771
      return vtype_is_signal(vt->elem);
53,207✔
2772
   default:
120,312✔
2773
      return false;
120,312✔
2774
   }
2775
}
2776

2777
int vtype_repr_bits(vtype_repr_t repr)
403,735✔
2778
{
2779
   switch (repr) {
403,735✔
2780
   case VCODE_REPR_U1: return 1;
2781
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2782
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2783
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2784
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2785
   default: return -1;
2786
   }
2787
}
2788

2789
bool vtype_repr_signed(vtype_repr_t repr)
41,651✔
2790
{
2791
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
41,651✔
2792
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
41,651✔
2793
}
2794

2795
static int64_t vtype_repr_low(vtype_repr_t repr)
7,788✔
2796
{
2797
   switch (repr) {
7,788✔
2798
   case VCODE_REPR_U1:
2799
   case VCODE_REPR_U8:
2800
   case VCODE_REPR_U16:
2801
   case VCODE_REPR_U32:
2802
   case VCODE_REPR_U64: return 0;
2803
   case VCODE_REPR_I8:  return INT8_MIN;
2804
   case VCODE_REPR_I16: return INT16_MIN;
2805
   case VCODE_REPR_I32: return INT32_MIN;
2806
   case VCODE_REPR_I64: return INT64_MIN;
2807
   default:             return 0;
2808
   }
2809
}
2810

2811
static uint64_t vtype_repr_high(vtype_repr_t repr)
7,788✔
2812
{
2813
   switch (repr) {
7,788✔
2814
   case VCODE_REPR_U1:  return 1;
2815
   case VCODE_REPR_U8:  return UINT8_MAX;
2816
   case VCODE_REPR_U16: return UINT16_MAX;
2817
   case VCODE_REPR_U32: return UINT32_MAX;
2818
   case VCODE_REPR_U64: return UINT64_MAX;
2819
   case VCODE_REPR_I8:  return INT8_MAX;
2820
   case VCODE_REPR_I16: return INT16_MAX;
2821
   case VCODE_REPR_I32: return INT32_MAX;
2822
   case VCODE_REPR_I64: return INT64_MAX;
2823
   default:             return 0;
2824
   }
2825
}
2826

2827
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
7,788✔
2828
{
2829
   int64_t clamp_low = vtype_repr_low(repr);
7,788✔
2830
   uint64_t clamp_high = vtype_repr_high(repr);
7,788✔
2831

2832
   if (*low >= clamp_low && *high <= clamp_high)
7,788✔
2833
      return true;
2834
   else {
2835
      *low = MAX(clamp_low, *low);
4,407✔
2836
      *high = MIN(clamp_high, *high);
4,407✔
2837
      return false;
4,407✔
2838
   }
2839
}
2840

2841
int vcode_count_params(void)
17,797✔
2842
{
2843
   assert(active_unit != NULL);
17,797✔
2844
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
17,797✔
2845
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2846
          || active_unit->kind == VCODE_UNIT_THUNK
2847
          || active_unit->kind == VCODE_UNIT_PROPERTY);
2848

2849
   return active_unit->params.count;
17,797✔
2850
}
2851

2852
vcode_type_t vcode_param_type(int param)
25,036✔
2853
{
2854
   assert(active_unit != NULL);
25,036✔
2855
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
25,036✔
2856
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2857
          || active_unit->kind == VCODE_UNIT_THUNK
2858
          || active_unit->kind == VCODE_UNIT_PROPERTY);
2859
   assert(param < active_unit->params.count);
25,036✔
2860

2861
   return active_unit->params.items[param].type;
25,036✔
2862
}
2863

2864
vcode_reg_t vcode_param_reg(int param)
32,151✔
2865
{
2866
   assert(active_unit != NULL);
32,151✔
2867
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
32,151✔
2868
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2869
          || active_unit->kind == VCODE_UNIT_THUNK
2870
          || active_unit->kind == VCODE_UNIT_PROPERTY);
2871
   assert(param < active_unit->params.count);
32,151✔
2872

2873
   return active_unit->params.items[param].reg;
32,151✔
2874
}
2875

2876
vcode_block_t emit_block(void)
112,513✔
2877
{
2878
   assert(active_unit != NULL);
112,513✔
2879

2880
   vcode_block_t bnum = active_unit->blocks.count;
112,513✔
2881

2882
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
112,513✔
2883
   memset(bptr, '\0', sizeof(block_t));
112,513✔
2884

2885
   if (active_block != VCODE_INVALID_BLOCK)
112,513✔
2886
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
77,970✔
2887
   else
2888
      bptr->last_loc = LOC_INVALID;
34,543✔
2889

2890
   return bnum;
112,513✔
2891
}
2892

2893
void vcode_select_unit(vcode_unit_t unit)
322,310✔
2894
{
2895
   active_unit  = unit;
322,310✔
2896
   active_block = VCODE_INVALID_BLOCK;
322,310✔
2897
}
322,310✔
2898

2899
void vcode_select_block(vcode_block_t block)
520,839✔
2900
{
2901
   assert(active_unit != NULL);
520,839✔
2902
   active_block = block;
520,839✔
2903
}
520,839✔
2904

2905
vcode_block_t vcode_active_block(void)
1,362,980✔
2906
{
2907
   assert(active_unit != NULL);
1,362,980✔
2908
   assert(active_block != -1);
1,362,980✔
2909
   return active_block;
1,362,980✔
2910
}
2911

2912
const loc_t *vcode_last_loc(void)
690,610✔
2913
{
2914
   return &(vcode_block_data()->last_loc);
690,610✔
2915
}
2916

2917
vcode_unit_t vcode_active_unit(void)
39,738✔
2918
{
2919
   assert(active_unit != NULL);
39,738✔
2920
   return active_unit;
39,738✔
2921
}
2922

2923
ident_t vcode_unit_name(void)
234,089✔
2924
{
2925
   assert(active_unit != NULL);
234,089✔
2926
   return active_unit->name;
234,089✔
2927
}
2928

2929
bool vcode_unit_has_undefined(void)
9,475✔
2930
{
2931
   assert(active_unit != NULL);
9,475✔
2932
   return !!(active_unit->flags & UNIT_UNDEFINED);
9,475✔
2933
}
2934

2935
bool vcode_unit_has_escaping_tlab(vcode_unit_t vu)
4,342✔
2936
{
2937
   return !!(vu->flags & UNIT_ESCAPING_TLAB);
4,342✔
2938
}
2939

2940
int vcode_unit_depth(void)
×
2941
{
2942
   assert(active_unit != NULL);
×
2943
   return active_unit->depth;
×
2944
}
2945

2946
void vcode_set_result(vcode_type_t type)
17,514✔
2947
{
2948
   assert(active_unit != NULL);
17,514✔
2949
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
17,514✔
2950
          || active_unit->kind == VCODE_UNIT_THUNK);
2951

2952
   active_unit->result = type;
17,514✔
2953
}
17,514✔
2954

2955
vcode_type_t vcode_unit_result(void)
34,702✔
2956
{
2957
   assert(active_unit != NULL);
34,702✔
2958
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
34,702✔
2959
          || active_unit->kind == VCODE_UNIT_THUNK);
2960
   return active_unit->result;
34,702✔
2961
}
2962

2963
vunit_kind_t vcode_unit_kind(void)
358,898✔
2964
{
2965
   assert(active_unit != NULL);
358,898✔
2966
   return active_unit->kind;
358,898✔
2967
}
2968

2969
vcode_unit_t vcode_unit_context(void)
104,248✔
2970
{
2971
   assert(active_unit != NULL);
104,248✔
2972
   return active_unit->context;
104,248✔
2973
}
2974

2975
object_t *vcode_unit_object(vcode_unit_t vu)
48,587✔
2976
{
2977
   assert(vu != NULL);
48,587✔
2978
   return object_from_locus(vu->module, vu->offset, lib_load_handler);
48,587✔
2979
}
2980

2981
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
44,027✔
2982
{
2983
   int hops = 0;
44,027✔
2984
   for (; (unit = unit->context); hops++)
89,577✔
2985
      ;
45,550✔
2986
   return hops;
44,027✔
2987
}
2988

2989
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
2990
{
2991
   if (context->kind == VCODE_UNIT_THUNK && child->kind != VCODE_UNIT_THUNK)
2992
      fatal_trace("thunk may not have non-thunk children");
2993

2994
   child->next = NULL;
2995
   if (context->children == NULL)
2996
      context->children = child;
2997
   else {
2998
      vcode_unit_t it;
2999
      for (it = context->children; it->next != NULL; it = it->next)
3000
         ;
3001
      it->next = child;
3002
   }
3003
}
3004

3005
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
9,068✔
3006
{
3007
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,068✔
3008
   vu->kind     = VCODE_UNIT_FUNCTION;
9,068✔
3009
   vu->name     = name;
9,068✔
3010
   vu->context  = context;
9,068✔
3011
   vu->result   = VCODE_INVALID_TYPE;
9,068✔
3012
   vu->depth    = vcode_unit_calc_depth(vu);
9,068✔
3013

3014
   object_locus(obj, &vu->module, &vu->offset);
9,068✔
3015

3016
   vcode_add_child(context, vu);
9,068✔
3017

3018
   vcode_select_unit(vu);
9,068✔
3019
   vcode_select_block(emit_block());
9,068✔
3020
   emit_debug_info(&(obj->loc));
9,068✔
3021

3022
   return vu;
9,068✔
3023
}
3024

3025
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
404✔
3026
{
3027
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
404✔
3028
   vu->kind     = VCODE_UNIT_PROCEDURE;
404✔
3029
   vu->name     = name;
404✔
3030
   vu->context  = context;
404✔
3031
   vu->result   = VCODE_INVALID_TYPE;
404✔
3032
   vu->depth    = vcode_unit_calc_depth(vu);
404✔
3033

3034
   object_locus(obj, &vu->module, &vu->offset);
404✔
3035

3036
   vcode_add_child(context, vu);
404✔
3037

3038
   vcode_select_unit(vu);
404✔
3039
   vcode_select_block(emit_block());
404✔
3040
   emit_debug_info(&(obj->loc));
404✔
3041

3042
   return vu;
404✔
3043
}
3044

3045
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
7,294✔
3046
{
3047
   assert(context->kind == VCODE_UNIT_INSTANCE);
7,294✔
3048

3049
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
7,294✔
3050
   vu->kind     = VCODE_UNIT_PROCESS;
7,294✔
3051
   vu->name     = name;
7,294✔
3052
   vu->context  = context;
7,294✔
3053
   vu->depth    = vcode_unit_calc_depth(vu);
7,294✔
3054
   vu->result   = VCODE_INVALID_TYPE;
7,294✔
3055

3056
   object_locus(obj, &vu->module, &vu->offset);
7,294✔
3057

3058
   vcode_add_child(context, vu);
7,294✔
3059

3060
   vcode_select_unit(vu);
7,294✔
3061
   vcode_select_block(emit_block());
7,294✔
3062
   emit_debug_info(&(obj->loc));
7,294✔
3063

3064
   return vu;
7,294✔
3065
}
3066

3067
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
6,767✔
3068
{
3069
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
6,767✔
3070

3071
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
6,767✔
3072
   vu->kind     = VCODE_UNIT_INSTANCE;
6,767✔
3073
   vu->name     = name;
6,767✔
3074
   vu->context  = context;
6,767✔
3075
   vu->depth    = vcode_unit_calc_depth(vu);
6,767✔
3076
   vu->result   = VCODE_INVALID_TYPE;
6,767✔
3077

3078
   object_locus(obj, &vu->module, &vu->offset);
6,767✔
3079

3080
   if (context != NULL)
6,767✔
3081
      vcode_add_child(context, vu);
3,890✔
3082

3083
   vcode_select_unit(vu);
6,767✔
3084
   vcode_select_block(emit_block());
6,767✔
3085
   emit_debug_info(&(obj->loc));
6,767✔
3086

3087
   return vu;
6,767✔
3088
}
3089

3090
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
1,329✔
3091
{
3092
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
1,329✔
3093
   vu->kind     = VCODE_UNIT_PACKAGE;
1,329✔
3094
   vu->name     = name;
1,329✔
3095
   vu->context  = context;
1,329✔
3096
   vu->depth    = vcode_unit_calc_depth(vu);
1,329✔
3097
   vu->result   = VCODE_INVALID_TYPE;
1,329✔
3098

3099
   object_locus(obj, &vu->module, &vu->offset);
1,329✔
3100

3101
   if (context != NULL)
1,329✔
3102
      vcode_add_child(context, vu);
127✔
3103

3104
   vcode_select_unit(vu);
1,329✔
3105
   vcode_select_block(emit_block());
1,329✔
3106
   emit_debug_info(&(obj->loc));
1,329✔
3107

3108
   return vu;
1,329✔
3109
}
3110

3111
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
149✔
3112
{
3113
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
149✔
3114
   vu->kind     = VCODE_UNIT_PROTECTED;
149✔
3115
   vu->name     = name;
149✔
3116
   vu->context  = context;
149✔
3117
   vu->depth    = vcode_unit_calc_depth(vu);
149✔
3118
   vu->result   = VCODE_INVALID_TYPE;
149✔
3119

3120
   object_locus(obj, &vu->module, &vu->offset);
149✔
3121

3122
   if (context != NULL)
149✔
3123
      vcode_add_child(context, vu);
149✔
3124

3125
   vcode_select_unit(vu);
149✔
3126
   vcode_select_block(emit_block());
149✔
3127
   emit_debug_info(&(obj->loc));
149✔
3128

3129
   return vu;
149✔
3130
}
3131

3132
vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context)
48✔
3133
{
3134
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
48✔
3135
   vu->kind     = VCODE_UNIT_PROPERTY;
48✔
3136
   vu->name     = name;
48✔
3137
   vu->context  = context;
48✔
3138
   vu->depth    = vcode_unit_calc_depth(vu);
48✔
3139
   vu->result   = VCODE_INVALID_TYPE;
48✔
3140

3141
   object_locus(obj, &vu->module, &vu->offset);
48✔
3142

3143
   if (context != NULL)
48✔
3144
      vcode_add_child(context, vu);
48✔
3145

3146
   vcode_select_unit(vu);
48✔
3147
   vcode_select_block(emit_block());
48✔
3148
   emit_debug_info(&(obj->loc));
48✔
3149

3150
   return vu;
48✔
3151
}
3152

3153
vcode_unit_t emit_thunk(ident_t name, object_t *obj, vcode_unit_t context)
9,484✔
3154
{
3155
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,484✔
3156
   vu->kind     = VCODE_UNIT_THUNK;
9,484✔
3157
   vu->name     = name;
9,484✔
3158
   vu->context  = context;
9,484✔
3159
   vu->depth    = vcode_unit_calc_depth(vu);
9,484✔
3160
   vu->result   = VCODE_INVALID_TYPE;
9,484✔
3161
   vu->depth    = vcode_unit_calc_depth(vu);
9,484✔
3162

3163
   object_locus(obj, &vu->module, &vu->offset);
9,484✔
3164

3165
   if (context != NULL)
9,484✔
3166
      vcode_add_child(context, vu);
125✔
3167

3168
   vcode_select_unit(vu);
9,484✔
3169
   vcode_select_block(emit_block());
9,484✔
3170

3171
   return vu;
9,484✔
3172
}
3173

3174
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
12,501✔
3175
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3176
                 vcode_reg_t hint_right)
3177
{
3178
   int64_t value_const;
12,501✔
3179
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
12,501✔
3180
      emit_comment("Always true assertion on r%d", value);
×
3181
      return;
×
3182
   }
3183

3184
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
12,501✔
3185
   vcode_add_arg(op, value);
12,501✔
3186
   vcode_add_arg(op, severity);
12,501✔
3187
   vcode_add_arg(op, message);
12,501✔
3188
   vcode_add_arg(op, length);
12,501✔
3189
   vcode_add_arg(op, locus);
12,501✔
3190

3191
   if (hint_left != VCODE_INVALID_REG) {
12,501✔
3192
      vcode_add_arg(op, hint_left);
5,051✔
3193
      vcode_add_arg(op, hint_right);
5,051✔
3194

3195
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
5,051✔
3196
                   "left hint must be scalar");
3197
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
5,051✔
3198
                   "right hint must be scalar");
3199
   }
3200

3201
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
12,501✔
3202
                "value parameter to assert is not bool");
3203
   VCODE_ASSERT(message == VCODE_INVALID_REG
12,501✔
3204
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3205
                "message parameter to assert is not a pointer");
3206
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
12,501✔
3207
                "value parameter to assert is not bool");
3208
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
12,501✔
3209
                "locus argument to report must be a debug locus");
3210
}
3211

3212
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
1,999✔
3213
                 vcode_reg_t locus)
3214
{
3215
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
1,999✔
3216
   vcode_add_arg(op, severity);
1,999✔
3217
   vcode_add_arg(op, message);
1,999✔
3218
   vcode_add_arg(op, length);
1,999✔
3219
   vcode_add_arg(op, locus);
1,999✔
3220

3221
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
1,999✔
3222
                "message parameter to report is not a pointer");
3223
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
1,999✔
3224
                "message parameter to report is not a character pointer");
3225
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,999✔
3226
                "locus argument to report must be a debug locus");
3227
}
1,999✔
3228

3229
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
32,715✔
3230
{
3231
   if (lhs == rhs) {
32,715✔
3232
      if (cmp == VCODE_CMP_EQ)
939✔
3233
         return emit_const(vtype_bool(), 1);
932✔
3234
      else if (cmp == VCODE_CMP_NEQ)
7✔
3235
         return emit_const(vtype_bool(), 0);
×
3236
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
7✔
3237
         return emit_const(vtype_bool(), 1);
×
3238
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
7✔
3239
         return emit_const(vtype_bool(), 0);
7✔
3240
   }
3241

3242
   int64_t lconst, rconst;
31,776✔
3243
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
31,776✔
3244
      switch (cmp) {
227✔
3245
      case VCODE_CMP_EQ:
226✔
3246
         return emit_const(vtype_bool(), lconst == rconst);
226✔
3247
      case VCODE_CMP_NEQ:
×
3248
         return emit_const(vtype_bool(), lconst != rconst);
×
3249
      case VCODE_CMP_LT:
×
3250
         return emit_const(vtype_bool(), lconst < rconst);
×
3251
      case VCODE_CMP_GT:
1✔
3252
         return emit_const(vtype_bool(), lconst > rconst);
1✔
3253
      case VCODE_CMP_LEQ:
×
3254
         return emit_const(vtype_bool(), lconst <= rconst);
×
3255
      case VCODE_CMP_GEQ:
×
3256
         return emit_const(vtype_bool(), lconst >= rconst);
×
3257
      default:
×
3258
         fatal_trace("cannot fold comparison %d", cmp);
×
3259
      }
3260
   }
3261

3262
   // Reuse any previous operation in this block with the same arguments
3263
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
580,406✔
3264
      if (other->args.count == 2 && other->args.items[0] == lhs
25,959✔
3265
          && other->args.items[1] == rhs && other->cmp == cmp)
1,348✔
3266
         return other->result;
355✔
3267
   }
3268

3269
   op_t *op = vcode_add_op(VCODE_OP_CMP);
31,194✔
3270
   vcode_add_arg(op, lhs);
31,194✔
3271
   vcode_add_arg(op, rhs);
31,194✔
3272
   op->cmp    = cmp;
31,194✔
3273
   op->result = vcode_add_reg(vtype_bool());
31,194✔
3274

3275
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
31,194✔
3276
                "arguments to cmp are not the same type");
3277

3278
   return op->result;
3279
}
3280

3281
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_type_t bounds,
30,171✔
3282
                       vcode_cc_t cc, const vcode_reg_t *args, int nargs)
3283
{
3284
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
30,171✔
3285
   o->func    = func;
30,171✔
3286
   o->type    = type;
30,171✔
3287
   o->subkind = cc;
30,171✔
3288
   for (int i = 0; i < nargs; i++)
115,273✔
3289
      vcode_add_arg(o, args[i]);
85,102✔
3290

3291
   for (int i = 0; i < nargs; i++)
115,273✔
3292
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
85,102✔
3293
                   "invalid argument to function");
3294

3295
   if (cc != VCODE_CC_FOREIGN && cc != VCODE_CC_VARIADIC)
30,171✔
3296
      VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
29,376✔
3297
                   "first argument to VHDL function must be context pointer");
3298

3299
   if (type == VCODE_INVALID_TYPE)
30,171✔
3300
      return (o->result = VCODE_INVALID_REG);
3,255✔
3301
   else {
3302
      o->result = vcode_add_reg(type);
26,916✔
3303

3304
      reg_t *rr = vcode_reg_data(o->result);
26,916✔
3305
      rr->bounds = bounds;
26,916✔
3306

3307
      return o->result;
26,916✔
3308
   }
3309
}
3310

3311
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
1,953✔
3312
                vcode_block_t resume_bb)
3313
{
3314
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
1,953✔
3315
   o->func    = func;
1,953✔
3316
   o->subkind = VCODE_CC_VHDL;
1,953✔
3317
   for (int i = 0; i < nargs; i++)
9,223✔
3318
      vcode_add_arg(o, args[i]);
7,270✔
3319

3320
   vcode_block_array_add(&(o->targets), resume_bb);
1,953✔
3321

3322
   for (int i = 0; i < nargs; i++)
9,223✔
3323
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
7,270✔
3324
                   "invalid argument to procedure");
3325

3326
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
1,953✔
3327
                "first argument to VHDL procedure must be context pointer");
3328
}
1,953✔
3329

3330
vcode_reg_t emit_alloc(vcode_type_t type, vcode_type_t bounds,
5,585✔
3331
                       vcode_reg_t count)
3332
{
3333
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
5,585✔
3334
   op->type    = type;
5,585✔
3335
   op->result  = vcode_add_reg(vtype_pointer(type));
5,585✔
3336
   vcode_add_arg(op, count);
5,585✔
3337

3338
   const vtype_kind_t tkind = vtype_kind(type);
5,585✔
3339
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
5,585✔
3340
                "alloca element type cannot be array");
3341
   VCODE_ASSERT(count != VCODE_INVALID_REG,
5,585✔
3342
                "alloca must have valid count argument");
3343

3344
   reg_t *r = vcode_reg_data(op->result);
5,585✔
3345
   r->bounds = bounds;
5,585✔
3346

3347
   return op->result;
5,585✔
3348
}
3349

3350
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
961,297✔
3351
{
3352
   // Reuse any previous constant in this block with the same type and value
3353
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
29,109,900✔
3354
      if (other->kind == VCODE_OP_CONST && other->value == value
7,997,590✔
3355
          && vtype_eq(type, other->type))
854,170✔
3356
         return other->result;
559,638✔
3357
   }
3358

3359
   op_t *op = vcode_add_op(VCODE_OP_CONST);
401,659✔
3360
   op->value  = value;
401,659✔
3361
   op->type   = type;
401,659✔
3362
   op->result = vcode_add_reg(type);
401,659✔
3363

3364
   vtype_kind_t type_kind = vtype_kind(type);
401,659✔
3365
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
401,659✔
3366
                "constant must have integer or offset type");
3367

3368
   reg_t *r = vcode_reg_data(op->result);
401,659✔
3369
   r->bounds = vtype_int(value, value);
401,659✔
3370

3371
   return op->result;
401,659✔
3372
}
3373

3374
vcode_reg_t emit_const_real(vcode_type_t type, double value)
33,145✔
3375
{
3376
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
1,183,860✔
3377
      if (other->real == value && other->type == type)
849,268✔
3378
         return other->result;
9,656✔
3379
   }
3380

3381
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
23,489✔
3382
   op->real   = value;
23,489✔
3383
   op->type   = type;
23,489✔
3384
   op->result = vcode_add_reg(op->type);
23,489✔
3385

3386
   reg_t *r = vcode_reg_data(op->result);
23,489✔
3387
   r->bounds = vtype_real(value, value);
23,489✔
3388

3389
   return op->result;
23,489✔
3390
}
3391

3392
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
25,205✔
3393
{
3394
   vtype_kind_t kind = vtype_kind(type);
25,205✔
3395

3396
   // Reuse any previous operation in this block with the same arguments
3397
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,031,870✔
3398
      if (other->args.count != num)
101,876✔
3399
         continue;
57,162✔
3400
      else if (!vtype_eq(vcode_reg_type(other->result), type))
44,714✔
3401
         continue;
423✔
3402

3403
      bool match = true;
3404
      for (int i = 0; match && i < num; i++) {
273,956✔
3405
         if (other->args.items[i] != values[i])
229,665✔
3406
            match = false;
39,635✔
3407
      }
3408

3409
      if (match) return other->result;
44,291✔
3410
   }
3411

3412
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
20,549✔
3413
   op->result = vcode_add_reg(type);
20,549✔
3414

3415
   for (int i = 0; i < num; i++)
1,130,370✔
3416
      vcode_add_arg(op, values[i]);
1,109,820✔
3417

3418
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
20,549✔
3419
                "constant array must have constrained array type");
3420
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
20,549✔
3421
                vtype_size(type), num);
3422

3423
#ifdef DEBUG
3424
   vcode_type_t elem = vtype_elem(type);
20,549✔
3425
   for (int i = 0; i < num; i++) {
1,130,370✔
3426
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,109,820✔
3427
                   "wrong element type for item %d", i);
3428
      vcode_assert_const(values[i], "array");
1,109,820✔
3429
   }
3430
#endif
3431

3432
   reg_t *r = vcode_reg_data(op->result);
20,549✔
3433
   r->bounds = vtype_elem(type);
20,549✔
3434

3435
   return op->result;
20,549✔
3436
}
3437

3438
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
935✔
3439
{
3440
   // Reuse any previous operation in this block with the same arguments
3441
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
16,955✔
3442
      if (other->args.items[0] == value && other->value == rep)
870✔
3443
         return other->result;
279✔
3444
   }
3445

3446
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
656✔
3447
   op->value = rep;
656✔
3448
   vcode_add_arg(op, value);
656✔
3449

3450
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
656✔
3451
                "constant array must have constrained array type");
3452

3453
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
656✔
3454

3455
   op->result = vcode_add_reg(type);
656✔
3456

3457
   reg_t *r = vcode_reg_data(op->result);
656✔
3458
   r->bounds = vtype_bounds(type);
656✔
3459

3460
   return op->result;
656✔
3461
}
3462

3463
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
1,980✔
3464
{
3465
   // Reuse any previous constant in this block with the same type and value
3466
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
46,704✔
3467
      if (vtype_eq(type, other->type) && other->args.count == num) {
1,439✔
3468
         bool same_regs = true;
3469
         for (int i = 0; i < num; i++)
2,964✔
3470
            same_regs = same_regs && other->args.items[i] == values[i];
3,525✔
3471

3472
         if (same_regs && vtype_eq(vcode_reg_type(other->result), type))
831✔
3473
            return other->result;
217✔
3474
      }
3475
   }
3476

3477
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
1,763✔
3478
   op->type   = type;
1,763✔
3479
   op->result = vcode_add_reg(type);
1,763✔
3480

3481
   for (int i = 0; i < num; i++)
7,043✔
3482
      vcode_add_arg(op, values[i]);
5,280✔
3483

3484
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
1,763✔
3485
                "constant record must have record type");
3486

3487
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
1,763✔
3488
                vtype_fields(type), num);
3489

3490
#ifdef DEBUG
3491
   for (int i = 0; i < num; i++) {
7,043✔
3492
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
5,280✔
3493
                   "wrong type for field %d", i);
3494
      vcode_assert_const(values[i], "record");
5,280✔
3495
   }
3496
#endif
3497

3498
   return op->result;
1,763✔
3499
}
3500

3501
vcode_reg_t emit_address_of(vcode_reg_t value)
26,662✔
3502
{
3503
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
1,100,370✔
3504
      if (other->args.items[0] == value)
103,281✔
3505
         return other->result;
4,690✔
3506
   }
3507

3508
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
21,972✔
3509
   vcode_add_arg(op, value);
21,972✔
3510

3511
   vcode_type_t type = vcode_reg_type(value);
21,972✔
3512
   VCODE_ASSERT(vtype_is_composite(type),
21,972✔
3513
                "address of argument must be record or array");
3514

3515
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
21,972✔
3516
      vcode_type_t elem = vtype_elem(type);
20,678✔
3517
      op->result = vcode_add_reg(vtype_pointer(elem));
20,678✔
3518

3519
      reg_t *rr = vcode_reg_data(op->result);
20,678✔
3520
      rr->bounds = elem;
20,678✔
3521

3522
      return op->result;
20,678✔
3523
   }
3524
   else
3525
      return (op->result = vcode_add_reg(vtype_pointer(type)));
1,294✔
3526
}
3527

3528
void emit_wait(vcode_block_t target, vcode_reg_t time)
10,537✔
3529
{
3530
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
10,537✔
3531
   vcode_add_target(op, target);
10,537✔
3532
   vcode_add_arg(op, time);
10,537✔
3533

3534
   VCODE_ASSERT(time == VCODE_INVALID_REG
10,537✔
3535
                || vcode_reg_kind(time) == VCODE_TYPE_INT,
3536
                "wait time must have integer type");
3537
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
10,537✔
3538
                || active_unit->kind == VCODE_UNIT_PROCESS,
3539
                "wait only allowed in process or procedure");
3540
}
10,537✔
3541

3542
void emit_jump(vcode_block_t target)
30,405✔
3543
{
3544
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
30,405✔
3545
   vcode_add_target(op, target);
30,405✔
3546
}
30,405✔
3547

3548
vcode_var_t emit_var(vcode_type_t type, vcode_type_t bounds, ident_t name,
36,494✔
3549
                     vcode_var_flags_t flags)
3550
{
3551
   assert(active_unit != NULL);
36,494✔
3552

3553
   vcode_var_t var = active_unit->vars.count;
36,494✔
3554
   var_t *v = var_array_alloc(&(active_unit->vars));
36,494✔
3555
   memset(v, '\0', sizeof(var_t));
36,494✔
3556
   v->type     = type;
36,494✔
3557
   v->bounds   = bounds;
36,494✔
3558
   v->name     = name;
36,494✔
3559
   v->flags    = flags;
36,494✔
3560

3561
   return var;
36,494✔
3562
}
3563

3564
vcode_reg_t emit_param(vcode_type_t type, vcode_type_t bounds, ident_t name)
25,764✔
3565
{
3566
   assert(active_unit != NULL);
25,764✔
3567

3568
   param_t *p = param_array_alloc(&(active_unit->params));
25,764✔
3569
   memset(p, '\0', sizeof(param_t));
25,764✔
3570
   p->type   = type;
25,764✔
3571
   p->bounds = bounds;
25,764✔
3572
   p->name   = name;
25,764✔
3573
   p->reg    = vcode_add_reg(type);
25,764✔
3574

3575
   reg_t *rr = vcode_reg_data(p->reg);
25,764✔
3576
   rr->bounds = bounds;
25,764✔
3577

3578
   return p->reg;
25,764✔
3579
}
3580

3581
vcode_reg_t emit_load(vcode_var_t var)
44,133✔
3582
{
3583
   // Try scanning backwards through the block for another load or store to
3584
   // this variable
3585
   vcode_reg_t fold = VCODE_INVALID_REG;
44,133✔
3586
   bool aliased = false;
44,133✔
3587
   VCODE_FOR_EACH_OP(other) {
488,973✔
3588
      if (fold == VCODE_INVALID_REG) {
452,924✔
3589
         if (other->kind == VCODE_OP_LOAD && other->address == var)
255,798✔
3590
            fold = other->result;
2,806✔
3591
         else if (other->kind == VCODE_OP_STORE && other->address == var)
252,992✔
3592
            fold = other->args.items[0];
9,664✔
3593
      }
3594

3595
      if (other->kind == VCODE_OP_INDEX && other->address == var)
452,924✔
3596
         aliased = true;
3597
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
452,855✔
3598
         break;   // Nested call captures variables
3599
      else if (other->kind == VCODE_OP_FILE_READ)
444,828✔
3600
         break;   // May write to variable
3601
   }
3602

3603
   var_t *v = vcode_var_data(var);
44,133✔
3604

3605
   if (fold != VCODE_INVALID_REG && !aliased)
44,133✔
3606
      return fold;
3607

3608
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
31,696✔
3609
   op->address = var;
31,696✔
3610
   op->result  = vcode_add_reg(v->type);
31,696✔
3611

3612
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
31,696✔
3613

3614
   reg_t *r = vcode_reg_data(op->result);
31,696✔
3615
   r->bounds = v->bounds;
31,696✔
3616

3617
   return op->result;
31,696✔
3618
}
3619

3620
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
66,570✔
3621
{
3622
   VCODE_FOR_EACH_OP(other) {
709,267✔
3623
      if (other->kind == VCODE_OP_LOAD_INDIRECT
664,855✔
3624
          && other->args.items[0] == reg) {
92,681✔
3625
         return other->result;
4,987✔
3626
      }
3627
      else if (other->kind == VCODE_OP_FCALL
659,868✔
3628
               || other->kind == VCODE_OP_PCALL
659,868✔
3629
               || other->kind == VCODE_OP_STORE
655,735✔
3630
               || other->kind == VCODE_OP_STORE_INDIRECT
647,894✔
3631
               || other->kind == VCODE_OP_MEMSET
645,360✔
3632
               || other->kind == VCODE_OP_COPY
645,128✔
3633
               || other->kind == VCODE_OP_FILE_READ)
642,709✔
3634
         break;   // May write to this pointer
3635
   }
3636

3637
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
61,583✔
3638
   vcode_add_arg(op, reg);
61,583✔
3639

3640
   vcode_type_t rtype = vcode_reg_type(reg);
61,583✔
3641

3642
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
61,583✔
3643
                "load indirect with non-pointer argument");
3644

3645
   vcode_type_t deref = vtype_pointed(rtype);
61,583✔
3646
   op->result = vcode_add_reg(deref);
61,583✔
3647

3648
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
61,583✔
3649

3650
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
61,583✔
3651

3652
   return op->result;
61,583✔
3653
}
3654

3655
void emit_store(vcode_reg_t reg, vcode_var_t var)
45,462✔
3656
{
3657
   // Any previous store to this variable in this block is dead
3658
   VCODE_FOR_EACH_OP(other) {
781,094✔
3659
      if (other->kind == VCODE_OP_STORE && other->address == var) {
745,315✔
3660
         other->kind = VCODE_OP_COMMENT;
245✔
3661
         other->comment =
490✔
3662
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
245✔
3663
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
245✔
3664
      }
3665
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
745,070✔
3666
         break;   // Needs to get variable for display
3667
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
739,896✔
3668
               && other->address == var)
15,758✔
3669
         break;   // Previous value may be used
3670
   }
3671

3672
   var_t *v = vcode_var_data(var);
45,462✔
3673
   reg_t *r = vcode_reg_data(reg);
45,462✔
3674

3675
   op_t *op = vcode_add_op(VCODE_OP_STORE);
45,462✔
3676
   vcode_add_arg(op, reg);
45,462✔
3677
   op->address = var;
45,462✔
3678

3679
   VCODE_ASSERT(vtype_eq(v->type, r->type),
45,462✔
3680
                "variable and stored value do not have same type");
3681
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
45,462✔
3682
}
45,462✔
3683

3684
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
9,618✔
3685
{
3686
   reg_t *p = vcode_reg_data(ptr);
9,618✔
3687
   reg_t *r = vcode_reg_data(reg);
9,618✔
3688

3689
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
9,618✔
3690
   vcode_add_arg(op, reg);
9,618✔
3691
   vcode_add_arg(op, ptr);
9,618✔
3692

3693
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
9,618✔
3694
                "store indirect target is not a pointer");
3695
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
9,618✔
3696
                "pointer and stored value do not have same type");
3697
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
9,618✔
3698
}
9,618✔
3699

3700
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
40,415✔
3701
                              vcode_reg_t locus)
3702
{
3703
   // Reuse any previous operation in this block with the same arguments
3704
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
982,137✔
3705
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
57,479✔
3706
         return other->result;
2,289✔
3707
   }
3708

3709
   op_t *op = vcode_add_op(kind);
38,126✔
3710
   vcode_add_arg(op, lhs);
38,126✔
3711
   vcode_add_arg(op, rhs);
38,126✔
3712
   if (locus != VCODE_INVALID_REG)
38,126✔
3713
      vcode_add_arg(op, locus);
4,685✔
3714

3715
   op->result = vcode_add_reg(vcode_reg_type(lhs));
38,126✔
3716

3717
   vcode_type_t lhs_type = vcode_reg_type(lhs);
38,126✔
3718
   vcode_type_t rhs_type = vcode_reg_type(rhs);
38,126✔
3719

3720
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
38,126✔
3721
                "arguments to %s are not the same type", vcode_op_string(kind));
3722

3723
   return op->result;
3724
}
3725

3726
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
29,097✔
3727
                               vcode_reg_t locus)
3728
{
3729
   int64_t lconst, rconst;
29,097✔
3730
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
29,097✔
3731
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
29,097✔
3732
   if (l_is_const && r_is_const)
29,097✔
3733
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
17,575✔
3734
   else if (r_is_const && rconst == 1)
11,522✔
3735
      return lhs;
3736
   else if (l_is_const && lconst == 1)
2,908✔
3737
      return rhs;
3738
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
2,636✔
3739
      return emit_const(vcode_reg_type(lhs), 0);
36✔
3740

3741
   reg_t *lhs_r = vcode_reg_data(lhs);
2,600✔
3742
   reg_t *rhs_r = vcode_reg_data(rhs);
2,600✔
3743

3744
   vtype_t *bl = vcode_type_data(lhs_r->bounds);
2,600✔
3745
   vtype_t *br = vcode_type_data(rhs_r->bounds);
2,600✔
3746

3747
   vcode_type_t vbounds;
2,600✔
3748
   if (vcode_reg_kind(lhs) == VCODE_TYPE_REAL) {
2,600✔
3749
      const double ll = bl->rlow * br->rlow;
711✔
3750
      const double lh = bl->rlow * br->rhigh;
711✔
3751
      const double hl = bl->rhigh * br->rlow;
711✔
3752
      const double hh = bl->rhigh * br->rhigh;
711✔
3753

3754
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,539✔
3755
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,749✔
3756

3757
      vbounds = vtype_real(min, max);
711✔
3758
   }
3759
   else {
3760
      const int64_t ll = smul64(bl->low, br->low);
1,889✔
3761
      const int64_t lh = smul64(bl->low, br->high);
1,889✔
3762
      const int64_t hl = smul64(bl->high, br->low);
1,889✔
3763
      const int64_t hh = smul64(bl->high, br->high);
1,889✔
3764

3765
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
1,889✔
3766
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
1,889✔
3767

3768
      vtype_repr_t repr = vtype_repr(lhs_r->type);
1,889✔
3769
      if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
1,889✔
3770
         op = VCODE_OP_MUL;   // Cannot overflow
363✔
3771
         locus = VCODE_INVALID_REG;
363✔
3772
      }
3773

3774
      vbounds = vtype_int(min, max);
1,889✔
3775
   }
3776

3777
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
2,600✔
3778

3779
   if (vbounds != VCODE_INVALID_TYPE)
2,600✔
3780
      vcode_reg_data(reg)->bounds = vbounds;
2,600✔
3781

3782
   return reg;
3783
}
3784

3785
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
28,302✔
3786
{
3787
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
28,302✔
3788
}
3789

3790
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
795✔
3791
{
3792
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
795✔
3793

3794
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
795✔
3795
                "trapping add may only be used with integer types");
3796

3797
   return result;
795✔
3798
}
3799

3800
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
550✔
3801
{
3802
   int64_t lconst, rconst;
550✔
3803
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
550✔
3804
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
550✔
3805
   if (l_is_const && r_is_const && rconst != 0)
550✔
3806
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
3✔
3807
   else if (r_is_const && rconst == 1)
547✔
3808
      return lhs;
3809

3810
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
546✔
3811

3812
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
546✔
3813

3814
   if (bl->kind == VCODE_TYPE_INT && r_is_const && rconst != 0) {
546✔
3815
      reg_t *rr = vcode_reg_data(reg);
272✔
3816
      rr->bounds = vtype_int(bl->low / rconst, bl->high / rconst);
272✔
3817
   }
3818
   else if (bl->kind == VCODE_TYPE_REAL) {
274✔
3819
      reg_t *rr = vcode_reg_data(reg);
209✔
3820
      rr->bounds = vtype_real(-INFINITY, INFINITY);
209✔
3821
   }
3822

3823
   return reg;
3824
}
3825

3826
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
78✔
3827
{
3828
   int64_t lconst, rconst;
78✔
3829
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
78✔
3830
       && rconst >= 0)
×
3831
      return emit_const(vcode_reg_type(lhs), ipow(lconst, rconst));
×
3832

3833
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
78✔
3834
}
3835

3836
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
535✔
3837
{
3838
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
535✔
3839

3840
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
535✔
3841
                "trapping exp may only be used with integer types");
3842

3843
   return result;
535✔
3844
}
3845

3846
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
171✔
3847
{
3848
   int64_t lconst, rconst;
171✔
3849
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
171✔
3850
       && lconst > 0 && rconst > 0)
14✔
3851
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
3✔
3852

3853
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
168✔
3854
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
168✔
3855

3856
   if (bl->low >= 0 && br->low >= 0) {
168✔
3857
      // If both arguments are non-negative then rem is equivalent and
3858
      // cheaper to compute
3859
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
27✔
3860

3861
      reg_t *rr = vcode_reg_data(reg);
27✔
3862
      rr->bounds = vtype_int(0, br->high - 1);
27✔
3863

3864
      return reg;
27✔
3865
   }
3866
   else
3867
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
141✔
3868
}
3869

3870
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
62✔
3871
{
3872
   int64_t lconst, rconst;
62✔
3873
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
62✔
3874
       && lconst > 0 && rconst > 0)
2✔
3875
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
3876

3877
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
62✔
3878

3879
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
62✔
3880
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
62✔
3881

3882
   if (bl->low >= 0 && br->low >= 0) {
62✔
3883
      reg_t *rr = vcode_reg_data(reg);
15✔
3884
      rr->bounds = vtype_int(0, br->high - 1);
15✔
3885
   }
3886

3887
   return reg;
3888
}
3889

3890
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
36,798✔
3891
                               vcode_reg_t locus)
3892
{
3893
   int64_t lconst, rconst;
36,798✔
3894
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
36,798✔
3895
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
36,798✔
3896
   if (l_is_const && r_is_const)
36,798✔
3897
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
16,798✔
3898
   else if (r_is_const && rconst == 0)
20,000✔
3899
      return lhs;
3900
   else if (l_is_const && lconst == 0)
19,982✔
3901
      return rhs;
3902

3903
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
12,555✔
3904
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
12,555✔
3905
      reg_t *lhs_r = vcode_reg_data(lhs);
12,307✔
3906
      reg_t *rhs_r = vcode_reg_data(rhs);
12,307✔
3907

3908
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
12,307✔
3909
      vtype_t *br = vcode_type_data(rhs_r->bounds);
12,307✔
3910

3911
      int64_t rbl = sadd64(bl->low, br->low);
12,307✔
3912
      int64_t rbh = sadd64(bl->high, br->high);
12,307✔
3913

3914
      vtype_repr_t repr = vtype_repr(lhs_r->type);
12,307✔
3915
      if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
12,307✔
3916
         op = VCODE_OP_ADD;   // Cannot overflow
748✔
3917
         locus = VCODE_INVALID_REG;
748✔
3918
      }
3919

3920
      vbounds = vtype_int(rbl, rbh);
12,307✔
3921
   }
3922

3923
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
12,555✔
3924

3925
   if (vbounds != VCODE_INVALID_TYPE)
12,555✔
3926
      vcode_reg_data(reg)->bounds = vbounds;
12,307✔
3927

3928
   return reg;
3929
}
3930

3931
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
34,138✔
3932
{
3933
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
34,138✔
3934
}
3935

3936
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
2,660✔
3937
{
3938
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
2,660✔
3939

3940
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
2,660✔
3941
                "trapping add may only be used with integer types");
3942

3943
   return result;
2,660✔
3944
}
3945

3946
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
31,702✔
3947
                               vcode_reg_t locus)
3948
{
3949
   int64_t lconst, rconst;
31,702✔
3950
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
31,702✔
3951
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
31,702✔
3952
   if (l_is_const && r_is_const)
31,702✔
3953
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
11,602✔
3954
   else if (r_is_const && rconst == 0)
20,100✔
3955
      return lhs;
3956
   else if (l_is_const && lconst == 0)
18,664✔
3957
      return emit_neg(rhs);
717✔
3958

3959
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
17,947✔
3960
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
17,947✔
3961
      reg_t *lhs_r = vcode_reg_data(lhs);
17,658✔
3962
      reg_t *rhs_r = vcode_reg_data(rhs);
17,658✔
3963

3964
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
17,658✔
3965
      vtype_t *br = vcode_type_data(rhs_r->bounds);
17,658✔
3966

3967
      int64_t rbl = ssub64(bl->low, br->high);
17,658✔
3968
      int64_t rbh = ssub64(bl->high, br->low);
17,658✔
3969

3970
      vtype_repr_t repr = vtype_repr(lhs_r->type);
17,658✔
3971
      if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
17,658✔
3972
         op = VCODE_OP_SUB;   // Cannot overflow
2,270✔
3973
         locus = VCODE_INVALID_REG;
2,270✔
3974
      }
3975

3976
      vbounds = vtype_int(rbl, rbh);
17,658✔
3977
   }
3978

3979
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
17,947✔
3980

3981
   if (vbounds != VCODE_INVALID_TYPE)
17,947✔
3982
      vcode_reg_data(reg)->bounds = vbounds;
17,658✔
3983

3984
   return reg;
3985
}
3986

3987
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
27,217✔
3988
{
3989
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
27,217✔
3990
}
3991

3992
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
4,485✔
3993
{
3994
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
4,485✔
3995

3996
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
4,485✔
3997
                "trapping sub may only be used with integer types");
3998

3999
   return result;
4,485✔
4000
}
4001

4002
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
4003
{
4004
   switch (vtype_kind(var->type)) {
4005
   case VCODE_TYPE_CARRAY:
4006
      op->type = vtype_pointer(vtype_elem(var->type));
4007
      op->result = vcode_add_reg(op->type);
4008
      vcode_reg_data(op->result)->bounds = vtype_bounds(var->type);
4009
      break;
4010

4011
   case VCODE_TYPE_RECORD:
4012
      op->type = vtype_pointer(var->type);
4013
      op->result = vcode_add_reg(op->type);
4014
      break;
4015

4016
   case VCODE_TYPE_INT:
4017
   case VCODE_TYPE_FILE:
4018
   case VCODE_TYPE_ACCESS:
4019
   case VCODE_TYPE_REAL:
4020
   case VCODE_TYPE_UARRAY:
4021
   case VCODE_TYPE_POINTER:
4022
   case VCODE_TYPE_SIGNAL:
4023
   case VCODE_TYPE_CONTEXT:
4024
   case VCODE_TYPE_OFFSET:
4025
   case VCODE_TYPE_TRIGGER:
4026
      op->type = vtype_pointer(var->type);
4027
      op->result = vcode_add_reg(op->type);
4028
      vcode_reg_data(op->result)->bounds = var->bounds;
4029
      break;
4030

4031
   default:
4032
      VCODE_ASSERT(false, "variable %s cannot be indexed",
4033
                   istr(var->name));
4034
   }
4035
}
4036

4037
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
18,697✔
4038
{
4039
   // Try to find a previous index of this var by this offset
4040
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
609,686✔
4041
      if (other->address == var
36,601✔
4042
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
5,341✔
4043
              || (offset != VCODE_INVALID_REG
×
4044
                  && other->args.items[0] == offset)))
×
4045
         return other->result;
5,341✔
4046
   }
4047

4048
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
13,356✔
4049
   op->address = var;
13,356✔
4050

4051
   if (offset != VCODE_INVALID_REG)
13,356✔
4052
      vcode_add_arg(op, offset);
×
4053

4054
   vcode_calculate_var_index_type(op, vcode_var_data(var));
13,356✔
4055

4056
   if (offset != VCODE_INVALID_REG)
13,356✔
4057
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4058
                   "index offset r%d does not have offset type", offset);
4059

4060
   return op->result;
13,356✔
4061
}
4062

4063
vcode_reg_t emit_cast(vcode_type_t type, vcode_type_t bounds, vcode_reg_t reg)
78,554✔
4064
{
4065
   if (vtype_eq(vcode_reg_type(reg), type))
78,554✔
4066
      return reg;
78,554✔
4067

4068
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
61,346✔
4069
   vtype_kind_t to   = vtype_kind(type);
61,346✔
4070

4071
   const bool integral =
122,692✔
4072
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
61,346✔
4073
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
61,346✔
4074

4075
   int64_t value;
61,346✔
4076
   if (integral && vcode_reg_const(reg, &value))
61,346✔
4077
      return emit_const(type, value);
12,280✔
4078

4079
   // Try to find a previous cast of this register to this type
4080
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
893,036✔
4081
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
106,807✔
4082
         return other->result;
10,518✔
4083
   }
4084

4085
   op_t *op = vcode_add_op(VCODE_OP_CAST);
38,548✔
4086
   vcode_add_arg(op, reg);
38,548✔
4087
   op->type   = type;
38,548✔
4088
   op->result = vcode_add_reg(type);
38,548✔
4089

4090
   static const vcode_type_t allowed[][2] = {
38,548✔
4091
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4092
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4093
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4094
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4095
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4096
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4097
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4098
   };
4099

4100
   if (from == VCODE_TYPE_INT && bounds == VCODE_INVALID_TYPE) {
38,548✔
4101
      reg_t *rr = vcode_reg_data(op->result);
7,576✔
4102
      rr->bounds = vcode_reg_bounds(reg);
7,576✔
4103
   }
4104
   else if (to == VCODE_TYPE_INT && bounds != VCODE_INVALID_TYPE) {
30,972✔
4105
      reg_t *rr = vcode_reg_data(op->result);
25,157✔
4106
      rr->bounds = bounds;
25,157✔
4107
   }
4108

4109
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
70,499✔
4110
      if (from == allowed[i][0] && to == allowed[i][1])
70,499✔
4111
         return op->result;
4112
   }
4113

4114
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4115
}
4116

4117
void emit_return(vcode_reg_t reg)
42,226✔
4118
{
4119
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
42,226✔
4120
   if (reg != VCODE_INVALID_REG) {
42,226✔
4121
      vcode_add_arg(op, reg);
23,745✔
4122

4123
      const vtype_kind_t rkind = vcode_reg_kind(reg);
23,745✔
4124
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
23,745✔
4125
         vcode_heap_allocate(reg);
7,107✔
4126
         active_unit->flags |= UNIT_ESCAPING_TLAB;
7,107✔
4127
      }
4128

4129
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
23,745✔
4130
                   || active_unit->kind == VCODE_UNIT_THUNK
4131
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4132
                   "returning value fron non-function unit");
4133
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
23,745✔
4134
                    && rkind == VCODE_TYPE_INT)
4135
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4136
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4137
                       && rkind == VCODE_TYPE_ACCESS),
4138
                   "return value incorrect type");
4139
   }
4140
}
42,226✔
4141

4142
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
8,353✔
4143
                         vcode_reg_t values, vcode_reg_t reject,
4144
                         vcode_reg_t after)
4145
{
4146
   int64_t nconst;
8,353✔
4147
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
8,353✔
4148
      emit_comment("Skip empty waveform");
3✔
4149
      return;
3✔
4150
   }
4151

4152
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
8,350✔
4153
   vcode_add_arg(op, nets);
8,350✔
4154
   vcode_add_arg(op, nnets);
8,350✔
4155
   vcode_add_arg(op, values);
8,350✔
4156
   vcode_add_arg(op, reject);
8,350✔
4157
   vcode_add_arg(op, after);
8,350✔
4158

4159
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
8,350✔
4160
                "sched_waveform target is not signal");
4161
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
8,350✔
4162
                "sched_waveform net count is not offset type");
4163
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
8,350✔
4164
                "signal cannot be values argument for sched_waveform");
4165
}
4166

4167
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
48✔
4168
{
4169
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
48✔
4170
   vcode_add_arg(op, nets);
48✔
4171
   vcode_add_arg(op, nnets);
48✔
4172
   vcode_add_arg(op, values);
48✔
4173

4174
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
48✔
4175
                "force target is not signal");
4176
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
48✔
4177
                "force net count is not offset type");
4178
}
48✔
4179

4180
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
24✔
4181
{
4182
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
24✔
4183
   vcode_add_arg(op, nets);
24✔
4184
   vcode_add_arg(op, nnets);
24✔
4185

4186
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
24✔
4187
                "release target is not signal");
4188
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
24✔
4189
                "release net count is not offset type");
4190
}
24✔
4191

4192
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
15✔
4193
                     vcode_reg_t after)
4194
{
4195
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
15✔
4196
   vcode_add_arg(op, nets);
15✔
4197
   vcode_add_arg(op, nnets);
15✔
4198
   vcode_add_arg(op, reject);
15✔
4199
   vcode_add_arg(op, after);
15✔
4200

4201
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
15✔
4202
                "disconnect target is not signal");
4203
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
15✔
4204
                "disconnect net count is not offset type");
4205
}
15✔
4206

4207
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
30,071✔
4208
{
4209
   int64_t tconst;
30,071✔
4210
   if (vcode_reg_const(test, &tconst)) {
30,071✔
4211
      emit_jump(!!tconst ? btrue : bfalse);
5,326✔
4212
      return;
3,261✔
4213
   }
4214

4215
   op_t *op = vcode_add_op(VCODE_OP_COND);
26,810✔
4216
   vcode_add_arg(op, test);
26,810✔
4217
   vcode_add_target(op, btrue);
26,810✔
4218
   vcode_add_target(op, bfalse);
26,810✔
4219

4220
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
26,810✔
4221
                "cond test is not a bool");
4222
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
26,810✔
4223
                "invalid cond targets");
4224
}
4225

4226
vcode_reg_t emit_neg(vcode_reg_t lhs)
6,614✔
4227
{
4228
   int64_t lconst;
6,614✔
4229
   if (vcode_reg_const(lhs, &lconst))
6,614✔
4230
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4231

4232
   op_t *op = vcode_add_op(VCODE_OP_NEG);
6,614✔
4233
   vcode_add_arg(op, lhs);
6,614✔
4234
   op->result = vcode_add_reg(vcode_reg_type(lhs));
6,614✔
4235

4236
   return op->result;
6,614✔
4237
}
4238

4239
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
768✔
4240
{
4241
   int64_t lconst;
768✔
4242
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
768✔
4243
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4244
   else if (vcode_type_data(vcode_reg_data(lhs)->bounds)->low >= 0)
768✔
4245
      return emit_neg(lhs);   // Cannot overflow
242✔
4246

4247
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
526✔
4248
   vcode_add_arg(op, lhs);
526✔
4249
   vcode_add_arg(op, locus);
526✔
4250

4251
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
526✔
4252
                "locus argument to trap neg must be a debug locus");
4253
   VCODE_ASSERT(vcode_reg_kind(lhs) == VCODE_TYPE_INT,
526✔
4254
                "trapping neg may only be used with integer types");
4255

4256
   return (op->result = vcode_add_reg(vcode_reg_type(lhs)));
526✔
4257
}
4258

4259
vcode_reg_t emit_abs(vcode_reg_t lhs)
222✔
4260
{
4261
   int64_t lconst;
222✔
4262
   if (vcode_reg_const(lhs, &lconst))
222✔
4263
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4264

4265
   op_t *op = vcode_add_op(VCODE_OP_ABS);
221✔
4266
   vcode_add_arg(op, lhs);
221✔
4267
   op->result = vcode_add_reg(vcode_reg_type(lhs));
221✔
4268

4269
   return op->result;
221✔
4270
}
4271

4272
void emit_comment(const char *fmt, ...)
30,123✔
4273
{
4274
#ifndef NDEBUG
4275
   va_list ap;
30,123✔
4276
   va_start(ap, fmt);
30,123✔
4277
   vcode_add_op(VCODE_OP_COMMENT)->comment = xvasprintf(fmt, ap);
30,123✔
4278
   va_end(ap);
30,123✔
4279
#endif
4280
}
30,123✔
4281

4282
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
14,859✔
4283
                        vcode_reg_t rfalse)
4284
{
4285
   int64_t tconst;
14,859✔
4286
   if (vcode_reg_const(test, &tconst))
14,859✔
4287
      return !!tconst ? rtrue : rfalse;
3,660✔
4288
   else if (rtrue == rfalse)
11,199✔
4289
      return rtrue;
4290

4291
   // Find a previous identical select
4292
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
287,308✔
4293
      if (other->args.items[0] == test && other->args.items[1] == rtrue
11,051✔
4294
          && other->args.items[2] == rfalse)
522✔
4295
         return other->result;
492✔
4296
   }
4297

4298
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
10,530✔
4299
   vcode_add_arg(op, test);
10,530✔
4300
   vcode_add_arg(op, rtrue);
10,530✔
4301
   vcode_add_arg(op, rfalse);
10,530✔
4302
   op->result = vcode_add_reg(vcode_reg_type(rtrue));
10,530✔
4303

4304
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
10,530✔
4305
                "select test must have bool type");
4306
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
10,530✔
4307
                "select arguments are not the same type");
4308

4309
   return op->result;
10,530✔
4310
}
4311

4312
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
91✔
4313
{
4314
   switch (op) {
91✔
4315
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
24✔
4316
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
19✔
4317
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
12✔
4318
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
12✔
4319
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
12✔
4320
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
12✔
4321
   default:
×
4322
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
×
4323
   }
4324
}
4325

4326
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
6,036✔
4327
{
4328
   vcode_type_t vtbool = vtype_bool();
6,036✔
4329

4330
   int64_t lconst, rconst;
6,036✔
4331
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
6,036✔
4332
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
6,036✔
4333
   if (l_is_const && r_is_const) {
6,036✔
4334
      switch (op) {
6✔
4335
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
4336
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
4337
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
×
4338
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
6✔
4339
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
4340
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
4341
      default:
×
4342
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
×
4343
      }
4344
   }
4345
   else if (l_is_const)
6,030✔
4346
      return emit_logical_identity(op, rhs, !!lconst);
12✔
4347
   else if (r_is_const)
6,018✔
4348
      return emit_logical_identity(op, lhs, !!rconst);
79✔
4349
   else if (lhs == rhs) {
5,939✔
4350
      switch (op) {
15✔
4351
      case VCODE_OP_AND:
4352
      case VCODE_OP_OR:
4353
         return lhs;
4354
      case VCODE_OP_NAND:
6✔
4355
      case VCODE_OP_NOR:
4356
         return emit_not(lhs);
6✔
4357
      case VCODE_OP_XOR:
3✔
4358
         return emit_const(vtbool, 0);
3✔
4359
      case VCODE_OP_XNOR:
×
4360
         return emit_const(vtbool, 1);
×
4361
      default:
×
4362
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
×
4363
      }
4364
   }
4365

4366
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
5,924✔
4367

4368
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
5,924✔
4369
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4370
                "arguments to %s are not boolean", vcode_op_string(op));
4371

4372
   return result;
4373
}
4374

4375
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
1,393✔
4376
{
4377
   return emit_logical(VCODE_OP_OR, lhs, rhs);
1,393✔
4378
}
4379

4380
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
4,342✔
4381
{
4382
   return emit_logical(VCODE_OP_AND, lhs, rhs);
4,342✔
4383
}
4384

4385
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
66✔
4386
{
4387
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
66✔
4388
}
4389

4390
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
67✔
4391
{
4392
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
67✔
4393
}
4394

4395
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
97✔
4396
{
4397
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
97✔
4398
}
4399

4400
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
71✔
4401
{
4402
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
71✔
4403
}
4404

4405
vcode_reg_t emit_not(vcode_reg_t arg)
1,793✔
4406
{
4407
   int64_t cval;
1,793✔
4408
   if (vcode_reg_const(arg, &cval))
1,793✔
4409
      return emit_const(vtype_bool(), !cval);
27✔
4410

4411
   op_t *op = vcode_add_op(VCODE_OP_NOT);
1,766✔
4412
   vcode_add_arg(op, arg);
1,766✔
4413

4414
   vcode_type_t vtbool = vtype_bool();
1,766✔
4415
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
1,766✔
4416
                "argument to not is not boolean");
4417

4418
   return (op->result = vcode_add_reg(vtbool));
1,766✔
4419
}
4420

4421
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
38,542✔
4422
{
4423
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,386,870✔
4424
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
158,744✔
4425
         bool match = true;
4426
         for (int i = 0; match && i < ndims; i++) {
11,782✔
4427
            match = other->args.items[i*3 + 1] == dims[i].left
5,911✔
4428
               && other->args.items[i*3 + 2] == dims[i].right
5,251✔
4429
               && other->args.items[i*3 + 3] == dims[i].dir;
11,138✔
4430
         }
4431
         if (match)
5,871✔
4432
            return other->result;
5,187✔
4433
      }
4434
   }
4435

4436
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
33,355✔
4437
   vcode_add_arg(op, data);
33,355✔
4438
   for (int i = 0; i < ndims; i++) {
67,106✔
4439
      vcode_add_arg(op, dims[i].left);
33,751✔
4440
      vcode_add_arg(op, dims[i].right);
33,751✔
4441
      vcode_add_arg(op, dims[i].dir);
33,751✔
4442
   }
4443

4444
   vcode_type_t ptr_type = vcode_reg_type(data);
33,355✔
4445
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
33,355✔
4446
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
33,355✔
4447
                "wrapped data is not pointer or signal");
4448

4449
#ifdef DEBUG
4450
   for (int i = 0; i < ndims; i++) {
67,106✔
4451
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
33,751✔
4452
                   "dimension %d left bound must be scalar", i + 1);
4453
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
33,751✔
4454
                   "dimension %d right bound must be scalar", i + 1);
4455
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
33,751✔
4456
                   "dimension %d direction must be bool", i + 1);
4457
   }
4458
#endif
4459

4460
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
66,710✔
4461
      ? vtype_pointed(ptr_type) : ptr_type;
33,355✔
4462

4463
   op->result = vcode_add_reg(
33,355✔
4464
      vtype_uarray(ndims, elem, vcode_reg_bounds(data)));
4465

4466
   return op->result;
33,355✔
4467
}
4468

4469
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
86,613✔
4470
                                  vcode_reg_t array, unsigned dim,
4471
                                  unsigned arg_index)
4472
{
4473
   // Reuse any previous operation in this block with the same arguments
4474
   VCODE_FOR_EACH_OP(other) {
967,032✔
4475
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
928,255✔
4476
          && (rtype == VCODE_INVALID_TYPE
16,230✔
4477
              || vtype_eq(rtype, vcode_reg_type(other->result))))
6,823✔
4478
         return other->result;
16,230✔
4479
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
912,025✔
4480
         return other->args.items[1 + (dim * 3) + arg_index];
31,606✔
4481
   }
4482

4483
   op_t *op = vcode_add_op(o);
38,777✔
4484
   vcode_add_arg(op, array);
38,777✔
4485
   op->dim = dim;
38,777✔
4486

4487
   vcode_type_t atype = vcode_reg_type(array);
38,777✔
4488
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
38,777✔
4489
                "cannot use %s with non-uarray type", vcode_op_string(o));
4490

4491
   vtype_t *vt = vcode_type_data(atype);
38,777✔
4492
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
38,777✔
4493

4494
   if (rtype == VCODE_INVALID_TYPE)
38,777✔
4495
      rtype = vtype_offset();
25,300✔
4496

4497
   return (op->result = vcode_add_reg(rtype));
38,777✔
4498
}
4499

4500
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
31,171✔
4501
{
4502
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
31,171✔
4503
                         array, dim, 0);
4504
}
4505

4506
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
24,548✔
4507
{
4508
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
24,548✔
4509
                         array, dim, 1);
4510
}
4511

4512
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
30,894✔
4513
{
4514
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
30,894✔
4515
                         array, dim, 2);
4516
}
4517

4518
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
39,740✔
4519
{
4520
   VCODE_FOR_EACH_OP(other) {
351,014✔
4521
      if (other->kind == VCODE_OP_UARRAY_LEN) {
331,241✔
4522
         if (other->args.items[0] == array && other->dim == dim)
27,762✔
4523
            return other->result;
9,553✔
4524
      }
4525
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
303,479✔
4526
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
10,414✔
4527
                      "array dimension %d out of bounds", dim);
4528

4529
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
10,414✔
4530
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
10,414✔
4531
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
10,414✔
4532
         return emit_range_length(left_reg, right_reg, dir_reg);
10,414✔
4533
      }
4534
   }
4535

4536
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
19,773✔
4537
   vcode_add_arg(op, array);
19,773✔
4538
   op->dim = dim;
19,773✔
4539

4540
   vcode_type_t atype = vcode_reg_type(array);
19,773✔
4541
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
19,773✔
4542
                "cannot use uarray len with non-uarray type");
4543

4544
   vtype_t *vt = vcode_type_data(atype);
19,773✔
4545
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
19,773✔
4546

4547
   return (op->result = vcode_add_reg(vtype_offset()));
19,773✔
4548
}
4549

4550
vcode_reg_t emit_unwrap(vcode_reg_t array)
29,718✔
4551
{
4552
   VCODE_FOR_EACH_OP(other) {
555,848✔
4553
      if (other->kind == VCODE_OP_WRAP && other->result == array)
534,948✔
4554
         return other->args.items[0];
8,133✔
4555
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
526,815✔
4556
         return other->result;
685✔
4557
   }
4558

4559
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
20,900✔
4560
   vcode_add_arg(op, array);
20,900✔
4561

4562
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
20,900✔
4563
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
20,900✔
4564
                "unwrap can only only be used with uarray types");
4565

4566
   vcode_type_t elem = vt->elem;
20,900✔
4567

4568
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
20,900✔
4569
      ? elem : vtype_pointer(elem);
20,900✔
4570

4571
   op->result = vcode_add_reg(rtype);
20,900✔
4572

4573
   reg_t *rr = vcode_reg_data(op->result);
20,900✔
4574
   rr->bounds = elem;
20,900✔
4575

4576
   return op->result;
20,900✔
4577
}
4578

4579
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
14,920✔
4580
                            vcode_reg_t dir)
4581
{
4582
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
447,258✔
4583
      if (other->args.items[0] == left
×
4584
          && other->args.items[1] == right
×
4585
          && other->args.items[2] == dir)
×
4586
         return other->result;
×
4587
   }
4588

4589
   int64_t dir_const;
14,920✔
4590
   if (vcode_reg_const(dir, &dir_const)) {
14,920✔
4591
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
11,020✔
4592
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
11,020✔
4593

4594
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
11,020✔
4595
         return emit_const(vtype_bool(), 1);
43✔
4596
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
10,977✔
4597
         return emit_const(vtype_bool(), 0);
4,941✔
4598
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
6,036✔
4599
         return emit_const(vtype_bool(), 1);
57✔
4600
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
5,979✔
4601
         return emit_const(vtype_bool(), 0);
1,456✔
4602
      else if (dir_const == RANGE_TO)
4,523✔
4603
         return emit_cmp(VCODE_CMP_GT, left, right);
1,212✔
4604
      else
4605
         return emit_cmp(VCODE_CMP_GT, right, left);
3,311✔
4606
   }
4607

4608
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
3,900✔
4609
   vcode_add_arg(op, left);
3,900✔
4610
   vcode_add_arg(op, right);
3,900✔
4611
   vcode_add_arg(op, dir);
3,900✔
4612

4613
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
3,900✔
4614
                "range left and right have different types");
4615
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
3,900✔
4616
                "dir argument to range length is not int");
4617

4618
   return (op->result = vcode_add_reg(vtype_bool()));
3,900✔
4619
}
4620

4621
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
14,460✔
4622
                              vcode_reg_t dir)
4623
{
4624
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_LENGTH) {
399,954✔
4625
      if (other->args.items[0] == left
5,114✔
4626
          && other->args.items[1] == right
4,124✔
4627
          && other->args.items[2] == dir)
3,886✔
4628
         return other->result;
3,886✔
4629
   }
4630

4631
   int64_t lconst, rconst, dconst;
10,574✔
4632
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
10,574✔
4633
       && vcode_reg_const(right, &rconst)) {
6,710✔
4634

4635
      int64_t diff;
5,334✔
4636
      if (dconst == RANGE_TO)
5,334✔
4637
         diff = rconst - lconst;
3,736✔
4638
      else
4639
         diff = lconst - rconst;
1,598✔
4640

4641
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
5,334✔
4642
   }
4643

4644
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
5,240✔
4645
   vcode_add_arg(op, left);
5,240✔
4646
   vcode_add_arg(op, right);
5,240✔
4647
   vcode_add_arg(op, dir);
5,240✔
4648

4649
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
5,240✔
4650
                "range left and right have different types");
4651
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
5,240✔
4652
                "dir argument to range length is not int");
4653

4654
   return (op->result = vcode_add_reg(vtype_offset()));
5,240✔
4655
}
4656

4657
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
37,216✔
4658
{
4659
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
561,246✔
4660
      if (other->hops == hops && other->address == var)
66,870✔
4661
         return other->result;
6,008✔
4662
   }
4663

4664
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
31,208✔
4665
   op->hops    = hops;
31,208✔
4666
   op->address = var;
31,208✔
4667

4668
   VCODE_ASSERT(hops > 0, "invalid hop count");
31,208✔
4669

4670
   vcode_unit_t vu = active_unit;
31,208✔
4671
   for (int i = 0; i < hops; i++) {
69,360✔
4672
      vu = vu->context;
38,152✔
4673
      VCODE_ASSERT(vu, "hop count is greater than depth");
38,152✔
4674
   }
4675

4676
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
31,208✔
4677

4678
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
31,208✔
4679

4680
   return op->result;
31,208✔
4681
}
4682

4683
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
8,579✔
4684
                             vcode_reg_t size, vcode_reg_t value,
4685
                             vcode_reg_t flags, vcode_reg_t locus,
4686
                             vcode_reg_t offset)
4687
{
4688
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
8,579✔
4689
   vcode_add_arg(op, count);
8,579✔
4690
   vcode_add_arg(op, size);
8,579✔
4691
   vcode_add_arg(op, value);
8,579✔
4692
   vcode_add_arg(op, flags);
8,579✔
4693
   vcode_add_arg(op, locus);
8,579✔
4694
   if (offset != VCODE_INVALID_REG)
8,579✔
4695
      vcode_add_arg(op, offset);
3,102✔
4696

4697
   vcode_type_t vtype = vcode_reg_type(value);
8,579✔
4698
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
8,579✔
4699
   VCODE_ASSERT(vtype_eq(vtype, type)
8,579✔
4700
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4701
                "init signal value type does not match signal type");
4702
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
8,579✔
4703
                "locus argument to init signal must be a debug locus");
4704
   VCODE_ASSERT(offset == VCODE_INVALID_REG
8,579✔
4705
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4706
                "init signal offset argument must have pointer type");
4707

4708
   return (op->result = vcode_add_reg(vtype_signal(type)));
8,579✔
4709
}
4710

4711
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
2,085✔
4712
{
4713
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
2,085✔
4714
   vcode_add_arg(op, signal);
2,085✔
4715
   vcode_add_arg(op, resolution);
2,085✔
4716

4717
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
2,085✔
4718
                "signal argument has wrong type");
4719
   VCODE_ASSERT(vcode_reg_kind(resolution) == VCODE_TYPE_RESOLUTION,
2,085✔
4720
                "resolution wrapper argument has wrong type");
4721
}
2,085✔
4722

4723
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
21✔
4724
                                 vcode_reg_t size, vcode_reg_t locus,
4725
                                 vcode_reg_t kind, vcode_reg_t closure)
4726
{
4727
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
21✔
4728
   vcode_add_arg(op, count);
21✔
4729
   vcode_add_arg(op, size);
21✔
4730
   vcode_add_arg(op, locus);
21✔
4731
   vcode_add_arg(op, kind);
21✔
4732
   vcode_add_arg(op, closure);
21✔
4733

4734
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
21✔
4735
                "count argument to implicit signal is not offset");
4736
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
21✔
4737
                "kind argument to implicit signal is not offset");
4738
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
21✔
4739
                "closure argument to implicit signal is not a closure");
4740
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
21✔
4741
                "locus argument to implicit signal must be a debug locus");
4742

4743
   return (op->result = vcode_add_reg(vtype_signal(type)));
21✔
4744
}
4745

4746
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t src_count,
918✔
4747
                     vcode_reg_t dst_count, vcode_reg_t conv)
4748
{
4749
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
918✔
4750
   vcode_add_arg(op, src);
918✔
4751
   vcode_add_arg(op, dst);
918✔
4752
   vcode_add_arg(op, src_count);
918✔
4753
   vcode_add_arg(op, dst_count);
918✔
4754
   if (conv != VCODE_INVALID_REG)
918✔
4755
      vcode_add_arg(op, conv);
249✔
4756

4757
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
918✔
4758
                "src argument to map signal is not a signal");
4759
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
918✔
4760
                "dst argument to map signal is not a signal");
4761
   VCODE_ASSERT(vcode_reg_kind(src_count) == VCODE_TYPE_OFFSET,
918✔
4762
                "src count argument type to map signal is not offset");
4763
   VCODE_ASSERT(vcode_reg_kind(dst_count) == VCODE_TYPE_OFFSET,
918✔
4764
                "dst count argument type to map signal is not offset");
4765
   VCODE_ASSERT(conv == VCODE_INVALID_REG
918✔
4766
                || vcode_reg_kind(conv) == VCODE_TYPE_CLOSURE,
4767
                "conv argument type to map signal is not closure");
4768
}
918✔
4769

4770
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
2,398✔
4771
{
4772
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
2,398✔
4773
   vcode_add_arg(op, src);
2,398✔
4774
   vcode_add_arg(op, dst);
2,398✔
4775
   vcode_add_arg(op, count);
2,398✔
4776

4777
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
2,398✔
4778
                "dst argument to map const is not a signal");
4779
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
2,398✔
4780
                "count argument type to map const is not offset");
4781
}
2,398✔
4782

4783
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
7,240✔
4784
{
4785
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
92,198✔
4786
      if (other->args.items[0] == target && other->args.items[1] == count)
13,076✔
4787
         return;
4788
   }
4789

4790
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
7,231✔
4791
   vcode_add_arg(op, target);
7,231✔
4792
   vcode_add_arg(op, count);
7,231✔
4793

4794
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
7,231✔
4795
                "target argument to drive signal is not a signal");
4796
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
7,231✔
4797
                "count argument type to drive signal is not offset");
4798
}
4799

4800
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
1,133✔
4801
                          vcode_reg_t count, vcode_reg_t reject,
4802
                          vcode_reg_t after)
4803
{
4804
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
1,133✔
4805
   vcode_add_arg(op, target);
1,133✔
4806
   vcode_add_arg(op, source);
1,133✔
4807
   vcode_add_arg(op, count);
1,133✔
4808
   vcode_add_arg(op, reject);
1,133✔
4809
   vcode_add_arg(op, after);
1,133✔
4810

4811
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
1,133✔
4812
                "target argument to transfer signal is not a signal");
4813
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
1,133✔
4814
                "count argument type to transfer signal is not offset");
4815
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
1,133✔
4816
                "source argument to transfer signal is not a signal");
4817
}
1,133✔
4818

4819
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
1,974✔
4820
                                    vcode_reg_t ileft, vcode_reg_t nlits)
4821
{
4822
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
99,808✔
4823
      if (other->args.items[0] == closure
1,414✔
4824
          && other->args.items[1] == ileft
1,411✔
4825
          && other->args.items[2] == nlits)
1,411✔
4826
         return other->result;
1,411✔
4827
   }
4828

4829
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
563✔
4830
                "first argument to resolution wrapper must be closure");
4831

4832
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
563✔
4833
   vcode_add_arg(op, closure);
563✔
4834
   vcode_add_arg(op, ileft);
563✔
4835
   vcode_add_arg(op, nlits);
563✔
4836
   op->subkind = VCODE_CC_VHDL;
563✔
4837

4838
   return (op->result = vcode_add_reg(vtype_resolution(type)));
563✔
4839
}
4840

4841
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t atype,
2,127✔
4842
                         vcode_type_t rtype)
4843
{
4844
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
103,971✔
4845
      if (other->func == func && other->subkind == VCODE_CC_VHDL
1,507✔
4846
          && other->args.items[0] == context)
1,432✔
4847
         return other->result;
1,432✔
4848
   }
4849

4850
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
695✔
4851
   vcode_add_arg(op, context);
695✔
4852
   op->func    = func;
695✔
4853
   op->subkind = VCODE_CC_VHDL;
695✔
4854
   op->type    = atype;
695✔
4855

4856
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
695✔
4857
                "invalid closure context argument");
4858

4859
   return (op->result = vcode_add_reg(vtype_closure(rtype)));
695✔
4860
}
4861

4862
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
23,625✔
4863
{
4864
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
32,840✔
4865
      if (other->func == name && other->subkind == VCODE_CC_VHDL)
18,441✔
4866
         return other->result;
10,451✔
4867
   }
4868

4869
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
13,174✔
4870
   op->func    = name;
13,174✔
4871
   op->subkind = VCODE_CC_VHDL;
13,174✔
4872
   if (context != VCODE_INVALID_REG)
13,174✔
4873
      vcode_add_arg(op, context);
127✔
4874

4875
   VCODE_ASSERT(context == VCODE_INVALID_REG
13,174✔
4876
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
4877
                "invalid protected init context argument");
4878
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
13,174✔
4879
                || active_unit->kind == VCODE_UNIT_PACKAGE
4880
                || active_unit->kind == VCODE_UNIT_THUNK,
4881
                "cannot use package init here");
4882
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
13,174✔
4883

4884
   return (op->result = vcode_add_reg(vtype_context(name)));
13,174✔
4885
}
4886

4887
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context)
136✔
4888
{
4889
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
136✔
4890
   vcode_add_arg(op, context);
136✔
4891
   op->func    = vtype_name(type);
136✔
4892
   op->subkind = VCODE_CC_VHDL;
136✔
4893

4894
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
136✔
4895
                "protected init type must be context");
4896
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
136✔
4897
                "invalid protected init context argument");
4898

4899
   return (op->result = vcode_add_reg(type));
136✔
4900
}
4901

4902
void emit_process_init(ident_t name, vcode_reg_t locus)
54✔
4903
{
4904
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
54✔
4905
   vcode_add_arg(op, locus);
54✔
4906
   op->func    = name;
54✔
4907
   op->subkind = VCODE_CC_VHDL;
54✔
4908

4909
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
54✔
4910
                "locus argument to process init must be a debug locus");
4911
}
54✔
4912

4913
void emit_protected_free(vcode_reg_t obj)
7✔
4914
{
4915
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
7✔
4916
   vcode_add_arg(op, obj);
7✔
4917

4918
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
7✔
4919
                "protected object type must be context");
4920
}
7✔
4921

4922
vcode_reg_t emit_context_upref(int hops)
14,180✔
4923
{
4924
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
428,042✔
4925
      if (other->hops == hops)
6,422✔
4926
         return other->result;
6,381✔
4927
   }
4928

4929
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
7,799✔
4930
   op->hops = hops;
7,799✔
4931

4932
   VCODE_ASSERT(hops >= 0, "invalid hop count");
7,799✔
4933

4934
   vcode_unit_t vu = active_unit;
7,799✔
4935
   for (int i = 0; i < hops; i++) {
14,758✔
4936
      vu = vu->context;
6,959✔
4937
      VCODE_ASSERT(vu, "hop count is greater than depth");
6,959✔
4938
   }
4939

4940
   return (op->result = vcode_add_reg(vtype_context(vu->name)));
7,799✔
4941
}
4942

4943
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
445✔
4944
                                    vcode_reg_t len)
4945
{
4946
   op_t *op = vcode_add_op(opkind);
445✔
4947
   vcode_add_arg(op, nets);
445✔
4948
   vcode_add_arg(op, len);
445✔
4949

4950
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
445✔
4951
                "argument to %s is not a signal", vcode_op_string(opkind));
4952

4953
   return (op->result = vcode_add_reg(vtype_bool()));
445✔
4954
}
4955

4956
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
255✔
4957
{
4958
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
255✔
4959
}
4960

4961
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
190✔
4962
{
4963
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
190✔
4964
}
4965

4966
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
27,702✔
4967
{
4968
   // Try scanning backwards through the block for another record ref
4969
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
1,777,270✔
4970
      if (other->args.items[0] == record && other->field == field)
386,840✔
4971
         return other->result;
1,734✔
4972
   }
4973

4974
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
25,968✔
4975
   op->field = field;
25,968✔
4976
   vcode_add_arg(op, record);
25,968✔
4977

4978
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
25,968✔
4979

4980
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
25,968✔
4981
                "argument to record ref must be a pointer");
4982

4983
   vtype_t *rtype = vcode_type_data(rptype->pointed);
25,968✔
4984
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
25,968✔
4985
                "argument must be pointer to record or record signal");
4986

4987
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
25,968✔
4988

4989
   vcode_type_t field_type  = rtype->fields.items[field];
25,968✔
4990
   vcode_type_t bounds_type = field_type;
25,968✔
4991
   vcode_type_t result_type = field_type;
25,968✔
4992

4993
   const vtype_kind_t fkind = vtype_kind(field_type);
25,968✔
4994
   if (fkind == VCODE_TYPE_CARRAY)
25,968✔
4995
      result_type = bounds_type = vtype_elem(field_type);
4,483✔
4996
   else if (fkind == VCODE_TYPE_UARRAY) {
21,485✔
4997
      bounds_type = vtype_elem(field_type);
1,752✔
4998
      result_type = field_type;
1,752✔
4999
   }
5000

5001
   op->result = vcode_add_reg(vtype_pointer(result_type));
25,968✔
5002

5003
   reg_t *rr = vcode_reg_data(op->result);
25,968✔
5004
   rr->bounds = bounds_type;
25,968✔
5005

5006
   return op->result;
25,968✔
5007
}
5008

5009
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
27,476✔
5010
{
5011
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
745,007✔
5012
      if (other->args.items[0] == array && other->args.items[1] == offset)
37,491✔
5013
         return other->result;
897✔
5014
   }
5015

5016
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
26,579✔
5017
   vcode_add_arg(op, array);
26,579✔
5018
   vcode_add_arg(op, offset);
26,579✔
5019

5020
   vcode_type_t rtype = vcode_reg_type(array);
26,579✔
5021
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
26,579✔
5022
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5023
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5024
                "argument to array ref must be a pointer or signal");
5025
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
26,579✔
5026
                "array ref offset argument must have offset type");
5027

5028
   op->result = vcode_add_reg(rtype);
26,579✔
5029

5030
   reg_t *rr = vcode_reg_data(op->result);
26,579✔
5031
   rr->bounds = vcode_reg_bounds(array);
26,579✔
5032

5033
   return op->result;
26,579✔
5034
}
5035

5036
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
17,145✔
5037
{
5038
   int64_t cconst;
17,145✔
5039
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
17,145✔
5040
       && cconst == 0)
8,076✔
5041
      return;
4,544✔
5042
   else if (dest == src)
17,037✔
5043
      return;
5044

5045
   op_t *op = vcode_add_op(VCODE_OP_COPY);
12,601✔
5046
   vcode_add_arg(op, dest);
12,601✔
5047
   vcode_add_arg(op, src);
12,601✔
5048
   if (count != VCODE_INVALID_REG)
12,601✔
5049
      vcode_add_arg(op, count);
11,151✔
5050

5051
   vcode_type_t dtype = vcode_reg_type(dest);
12,601✔
5052
   vcode_type_t stype = vcode_reg_type(src);
12,601✔
5053

5054
   vtype_kind_t dkind = vtype_kind(dtype);
12,601✔
5055
   vtype_kind_t skind = vtype_kind(stype);
12,601✔
5056

5057
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
12,601✔
5058
                "destination type is not a pointer or access");
5059
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
12,601✔
5060
                "source type is not a pointer or access");
5061
   VCODE_ASSERT(vtype_eq(dtype, stype),
12,601✔
5062
                "source and destination types do not match");
5063
   VCODE_ASSERT(count == VCODE_INVALID_REG
12,601✔
5064
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5065
                "count is not offset type");
5066

5067
   op->type = vtype_pointed(dtype);
12,601✔
5068
}
5069

5070
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
3,957✔
5071
{
5072
   VCODE_FOR_EACH_OP(other) {
59,459✔
5073
      if (other->kind == VCODE_OP_CLEAR_EVENT)
55,534✔
5074
         break;
5075
      else if (other->kind == VCODE_OP_SCHED_EVENT
55,504✔
5076
               && other->args.items[0] == nets
3,922✔
5077
               && other->args.items[1] == n_elems)
5✔
5078
         return;
5079
   }
5080

5081
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
3,955✔
5082
   vcode_add_arg(op, nets);
3,955✔
5083
   vcode_add_arg(op, n_elems);
3,955✔
5084

5085
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
3,955✔
5086
                "nets argument to sched event must be signal");
5087
}
5088

5089
void emit_implicit_event(vcode_reg_t nets, vcode_reg_t count, vcode_reg_t wake)
18✔
5090
{
5091
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_IMPLICIT_EVENT) {
234✔
5092
      if (other->args.items[0] == nets && other->args.items[1] == count
×
5093
          && other->args.items[1] == wake)
×
5094
         return;
5095
   }
5096

5097
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_EVENT);
18✔
5098
   vcode_add_arg(op, nets);
18✔
5099
   vcode_add_arg(op, count);
18✔
5100
   vcode_add_arg(op, wake);
18✔
5101

5102
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
18✔
5103
                "nets argument to implicit event must be signal");
5104
   VCODE_ASSERT(vcode_reg_kind(wake) == VCODE_TYPE_SIGNAL,
18✔
5105
                "wake argument to implicit event must be signal");
5106
}
5107

5108
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
450✔
5109
{
5110
   VCODE_FOR_EACH_OP(other) {
2,118✔
5111
      if (other->kind == VCODE_OP_SCHED_EVENT)
1,669✔
5112
         break;
5113
      else if (other->kind == VCODE_OP_CLEAR_EVENT
1,669✔
5114
               && other->args.items[0] == nets
40✔
5115
               && other->args.items[1] == n_elems)
1✔
5116
         return;
5117
   }
5118

5119
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
449✔
5120
   vcode_add_arg(op, nets);
449✔
5121
   vcode_add_arg(op, n_elems);
449✔
5122

5123
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
449✔
5124
                "nets argument to clear event must be signal");
5125
}
5126

5127
void emit_resume(ident_t func)
1,953✔
5128
{
5129
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
1,953✔
5130
   op->func = func;
1,953✔
5131

5132
   block_t *b = &(active_unit->blocks.items[active_block]);
1,953✔
5133
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
1,953✔
5134
}
1,953✔
5135

5136
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
5,160✔
5137
{
5138
   int64_t lconst;
5,160✔
5139
   if (vcode_reg_const(len, &lconst) && lconst == 0)
5,160✔
5140
      return;
17✔
5141

5142
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
5,143✔
5143
   vcode_add_arg(op, ptr);
5,143✔
5144
   vcode_add_arg(op, value);
5,143✔
5145
   vcode_add_arg(op, len);
5,143✔
5146

5147
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
5,143✔
5148
                "target of memset must have pointer type");
5149
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
5,143✔
5150
                "value of memset must have scalar type");
5151
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
5,143✔
5152
                "length of memset must have offset type");
5153
}
5154

5155
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
433✔
5156
               const vcode_block_t *blocks, int ncases)
5157
{
5158
   int64_t cval1, cval2;
433✔
5159
   bool is_const = vcode_reg_const(value, &cval1);
433✔
5160

5161
   for (int i = 0; i < ncases; i++) {
4,245✔
5162
      bool can_fold = false;
3,816✔
5163
      if (cases[i] == value)
3,816✔
5164
         can_fold = true;
5165
      else if (is_const && vcode_reg_const(cases[i], &cval2))
3,816✔
5166
         can_fold = (cval1 == cval2);
4✔
5167

5168
      if (can_fold) {
4✔
5169
         emit_jump(blocks[i]);
4✔
5170
         return;
8✔
5171
      }
5172
   }
5173

5174
   if (is_const) {
429✔
5175
      emit_jump(def);
×
5176
      return;
×
5177
   }
5178

5179
   op_t *op = vcode_add_op(VCODE_OP_CASE);
429✔
5180
   vcode_add_arg(op, value);
429✔
5181
   vcode_add_target(op, def);
429✔
5182

5183
   for (int i = 0; i < ncases; i++) {
4,241✔
5184
      vcode_add_arg(op, cases[i]);
3,812✔
5185
      vcode_add_target(op, blocks[i]);
3,812✔
5186

5187
#ifdef DEBUG
5188
      for (int j = 0; j < i; j++)
242,053✔
5189
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
238,241✔
5190
#endif
5191
   }
5192
}
5193

5194
vcode_reg_t emit_endfile(vcode_reg_t file)
27✔
5195
{
5196
   op_t *op = vcode_add_op(VCODE_OP_ENDFILE);
27✔
5197
   vcode_add_arg(op, file);
27✔
5198

5199
   VCODE_ASSERT(vtype_kind(vcode_reg_type(file)) == VCODE_TYPE_FILE,
27✔
5200
                "endfile argument must have file type");
5201

5202
   return (op->result = vcode_add_reg(vtype_bool()));
27✔
5203
}
5204

5205
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
213✔
5206
                    vcode_reg_t kind, vcode_reg_t status)
5207
{
5208
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
213✔
5209
   vcode_add_arg(op, file);
213✔
5210
   vcode_add_arg(op, name);
213✔
5211
   vcode_add_arg(op, length);
213✔
5212
   vcode_add_arg(op, kind);
213✔
5213
   if (status != VCODE_INVALID_REG)
213✔
5214
      vcode_add_arg(op, status);
21✔
5215

5216
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
213✔
5217
                "file open first argument must have file pointer type");
5218
}
213✔
5219

5220
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
113✔
5221
{
5222
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
113✔
5223
   vcode_add_arg(op, file);
113✔
5224
   vcode_add_arg(op, value);
113✔
5225
   if (length != VCODE_INVALID_REG)
113✔
5226
      vcode_add_arg(op, length);
65✔
5227

5228
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
113✔
5229
                "file write first argument must have file pointer type");
5230
}
113✔
5231

5232
void emit_file_close(vcode_reg_t file)
136✔
5233
{
5234
   op_t *op = vcode_add_op(VCODE_OP_FILE_CLOSE);
136✔
5235
   vcode_add_arg(op, file);
136✔
5236

5237
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
136✔
5238
                "file close argument must have file pointer type");
5239
}
136✔
5240

5241
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
69✔
5242
                    vcode_reg_t inlen, vcode_reg_t outlen)
5243
{
5244
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
69✔
5245
   vcode_add_arg(op, file);
69✔
5246
   vcode_add_arg(op, ptr);
69✔
5247
   if (inlen != VCODE_INVALID_REG) {
69✔
5248
      vcode_add_arg(op, inlen);
27✔
5249
      if (outlen != VCODE_INVALID_REG)
27✔
5250
         vcode_add_arg(op, outlen);
18✔
5251
   }
5252

5253
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
69✔
5254
                "file read first argument must have file pointer type");
5255
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
69✔
5256
                "file read pointer argument must have pointer type");
5257
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
69✔
5258
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5259
                "file read outlen argument must have pointer type");
5260
}
69✔
5261

5262
vcode_reg_t emit_null(vcode_type_t type)
5,801✔
5263
{
5264
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
97,110✔
5265
      if (vtype_eq(vcode_reg_type(other->result), type))
1,804✔
5266
         return other->result;
755✔
5267
   }
5268

5269
   op_t *op = vcode_add_op(VCODE_OP_NULL);
5,046✔
5270
   op->result = vcode_add_reg(type);
5,046✔
5271

5272
   vtype_kind_t kind = vtype_kind(type);
5,046✔
5273
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
5,046✔
5274
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5275
                "null type must be file, access, context, or pointer");
5276

5277
   return op->result;
5278
}
5279

5280
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
418✔
5281
{
5282
   op_t *op = vcode_add_op(VCODE_OP_NEW);
418✔
5283
   if (length != VCODE_INVALID_REG)
418✔
5284
      vcode_add_arg(op, length);
330✔
5285

5286
   op->result = vcode_add_reg(vtype_access(type));
418✔
5287

5288
   vtype_kind_t kind = vtype_kind(type);
418✔
5289
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
418✔
5290
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5291
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5292
                "new type must be int, real, record, access, or uarray");
5293
   VCODE_ASSERT(length == VCODE_INVALID_REG
418✔
5294
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5295
                "new length must have offset type");
5296

5297
   return op->result;
418✔
5298
}
5299

5300
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
1,749✔
5301
{
5302
   VCODE_FOR_EACH_OP(other) {
144,018✔
5303
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
142,538✔
5304
         return;
5305
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
142,383✔
5306
         return;
5307
   }
5308

5309
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
1,480✔
5310
   vcode_add_arg(op, ptr);
1,480✔
5311
   vcode_add_arg(op, locus);
1,480✔
5312

5313
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
1,480✔
5314
                "null check argument must be an access");
5315
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,480✔
5316
                "locus argument to null check must be a debug locus");
5317
}
5318

5319
void emit_deallocate(vcode_reg_t ptr)
207✔
5320
{
5321
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
207✔
5322
   vcode_add_arg(op, ptr);
207✔
5323

5324
   vcode_type_t ptype = vcode_reg_type(ptr);
207✔
5325
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
207✔
5326
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5327
                "deallocate argument must be pointer to access");
5328
}
207✔
5329

5330
vcode_reg_t emit_all(vcode_reg_t reg)
2,167✔
5331
{
5332
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
157,909✔
5333
      if (other->args.items[0] == reg)
15,244✔
5334
         return other->result;
269✔
5335
   }
5336

5337
   op_t *op = vcode_add_op(VCODE_OP_ALL);
1,898✔
5338
   vcode_add_arg(op, reg);
1,898✔
5339

5340
   vcode_type_t vtype = vcode_reg_type(reg);
1,898✔
5341

5342
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
1,898✔
5343
                "all argument must be an access");
5344

5345
   vcode_type_t pointed = vtype_pointed(vtype);
1,898✔
5346
   op->result = vcode_add_reg(vtype_pointer(pointed));
1,898✔
5347

5348
   reg_t *rr = vcode_reg_data(op->result);
1,898✔
5349
   rr->bounds = pointed;
1,898✔
5350

5351
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
1,898✔
5352
                "cannot dereference opaque type");
5353

5354
   return op->result;
5355
}
5356

5357
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
11,313✔
5358
{
5359
   block_t *b = &(active_unit->blocks.items[active_block]);
11,313✔
5360
   for (int i = b->ops.count - 1; i >= 0; i--) {
361,643✔
5361
      const op_t *other = &(b->ops.items[i]);
350,970✔
5362
      if (other->kind == kind && other->args.items[0] == sig)
350,970✔
5363
         return other->result;
640✔
5364
   }
5365

5366
   op_t *op = vcode_add_op(kind);
10,673✔
5367
   vcode_add_arg(op, sig);
10,673✔
5368

5369
   vcode_type_t stype = vcode_reg_type(sig);
10,673✔
5370
   op->type = stype;
10,673✔
5371

5372
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
10,673✔
5373
                "argument r%d to resolved is not a signal", sig);
5374

5375
   vcode_type_t rtype = vtype_base(stype);
10,673✔
5376

5377
   const vtype_kind_t rkind = vtype_kind(rtype);
10,673✔
5378
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
10,673✔
5379
      rtype = vtype_elem(rtype);
×
5380

5381
   VCODE_ASSERT(vtype_is_scalar(rtype),
10,673✔
5382
                "resolved signal base type must be scalar");
5383

5384
   op->result = vcode_add_reg(vtype_pointer(rtype));
10,673✔
5385

5386
   reg_t *rr = vcode_reg_data(op->result);
10,673✔
5387
   rr->bounds = rtype;
10,673✔
5388

5389
   return op->result;
10,673✔
5390
}
5391

5392
vcode_reg_t emit_resolved(vcode_reg_t sig)
11,272✔
5393
{
5394
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
11,272✔
5395
}
5396

5397
vcode_reg_t emit_last_value(vcode_reg_t sig)
41✔
5398
{
5399
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
41✔
5400
}
5401

5402
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
42✔
5403
{
5404
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
42✔
5405
   vcode_add_arg(op, signal);
42✔
5406
   if (len != VCODE_INVALID_REG)
42✔
5407
      vcode_add_arg(op, len);
30✔
5408

5409
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
42✔
5410
                "signal argument to last event must have signal type");
5411
   VCODE_ASSERT(len == VCODE_INVALID_REG
42✔
5412
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5413
                "length argument to last event must have offset type");
5414

5415
   return (op->result = vcode_add_reg(vtype_time()));
42✔
5416
}
5417

5418
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
36✔
5419
{
5420
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
36✔
5421
   vcode_add_arg(op, signal);
36✔
5422
   if (len != VCODE_INVALID_REG)
36✔
5423
      vcode_add_arg(op, len);
27✔
5424

5425
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5426
                "signal argument to last active must have signal type");
5427
   VCODE_ASSERT(len == VCODE_INVALID_REG
36✔
5428
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5429
                "length argument to last active must have offset type");
5430

5431
   return (op->result = vcode_add_reg(vtype_time()));
36✔
5432
}
5433

5434
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,303✔
5435
{
5436
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,303✔
5437
   vcode_add_arg(op, signal);
4,303✔
5438
   vcode_add_arg(op, locus);
4,303✔
5439

5440
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,303✔
5441
                "signal argument must have signal type");
5442
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
4,303✔
5443
                "locus argument must have debug locus type");
5444
}
4,303✔
5445

5446
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
30✔
5447
{
5448
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
30✔
5449
   vcode_add_arg(op, signal);
30✔
5450
   vcode_add_arg(op, len);
30✔
5451

5452
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
30✔
5453
                "signal argument to last active must have signal type");
5454
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
30✔
5455
                "length argument to last active must have offset type");
5456

5457
   return (op->result = vcode_add_reg(vtype_bool()));
30✔
5458
}
5459

5460
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
24✔
5461
{
5462
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
24✔
5463
   vcode_add_arg(op, signal);
24✔
5464
   if (len != VCODE_INVALID_REG)
24✔
5465
      vcode_add_arg(op, len);
3✔
5466

5467
   vcode_type_t signal_type = vcode_reg_type(signal);
24✔
5468

5469
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
24✔
5470
                "signal argument to last active must have signal type");
5471
   VCODE_ASSERT(len == VCODE_INVALID_REG
24✔
5472
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5473
                "length argument to last active must have offset type");
5474

5475
   vcode_type_t base_type = vtype_base(signal_type);
24✔
5476
   op->result = vcode_add_reg(vtype_pointer(base_type));
24✔
5477

5478
   reg_t *rr = vcode_reg_data(op->result);
24✔
5479
   rr->bounds = base_type;
24✔
5480

5481
   return op->result;
24✔
5482
}
5483

5484
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
16,069✔
5485
                       vcode_reg_t dim)
5486
{
5487
   if (rlen == llen)
16,069✔
5488
      return;
5489

5490
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
101,130✔
5491
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
1,790✔
5492
         return;
5493
   }
5494

5495
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
5,132✔
5496
   vcode_add_arg(op, llen);
5,132✔
5497
   vcode_add_arg(op, rlen);
5,132✔
5498
   vcode_add_arg(op, locus);
5,132✔
5499
   if (dim != VCODE_INVALID_REG)
5,132✔
5500
      vcode_add_arg(op, dim);
24✔
5501

5502
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
5,132✔
5503
                "locus argument to length check must be a debug locus");
5504
}
5505

5506
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
535✔
5507
{
5508
   int64_t cval;
535✔
5509
   if (vcode_reg_const(exp, &cval) && cval >= 0)
535✔
5510
      return;
30✔
5511

5512
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
3,078✔
5513
      if (other->args.items[0] == exp)
3✔
5514
         return;
5515
   }
5516

5517
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
505✔
5518
   vcode_add_arg(op, exp);
505✔
5519
   vcode_add_arg(op, locus);
505✔
5520

5521
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
505✔
5522
                "exp argument to exponent check must be a integer");
5523
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
505✔
5524
                "locus argument to exponent check must be a debug locus");
5525
}
5526

5527
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
541✔
5528
{
5529
   int64_t cval;
541✔
5530
   if (vcode_reg_const(denom, &cval) && cval != 0)
541✔
5531
      return;
446✔
5532

5533
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
3,469✔
5534
      if (other->args.items[0] == denom)
56✔
5535
         return;
5536
   }
5537

5538
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
95✔
5539
   vcode_add_arg(op, denom);
95✔
5540
   vcode_add_arg(op, locus);
95✔
5541

5542
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
95✔
5543
                "denom argument to zero check must be a integer");
5544
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
95✔
5545
                "locus argument to zero check must be a debug locus");
5546
}
5547

5548
bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
82,888✔
5549
                            vcode_reg_t right, vcode_reg_t dir)
5550
{
5551
   int64_t dconst;
82,888✔
5552
   if (vcode_reg_const(dir, &dconst)) {
82,888✔
5553
      int64_t lconst, rconst;
76,278✔
5554
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
76,278✔
5555
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
68,619✔
5556
            || (dconst == RANGE_DOWNTO && rconst > lconst);
139,907✔
5557

5558
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
71,288✔
5559

5560
         const bool ok_static =
142,576✔
5561
            (dconst == RANGE_TO
5562
             && bounds->low >= lconst && bounds->high <= rconst)
68,619✔
5563
            || (dconst == RANGE_DOWNTO
8,801✔
5564
                && bounds->low >= rconst && bounds->high <= lconst)
2,669✔
5565
            || (!is_null && (reg == left || reg == right));
77,531✔
5566

5567
         return ok_static;
75,136✔
5568
      }
5569
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
4,990✔
5570
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
4,607✔
5571
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
4,607✔
5572

5573
         assert(lbounds->kind == VCODE_TYPE_REAL);
4,607✔
5574
         assert(rbounds->kind == VCODE_TYPE_REAL);
4,607✔
5575

5576
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
4,607✔
5577
         assert(bounds->kind == VCODE_TYPE_REAL);
4,607✔
5578

5579
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
4,607✔
5580
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
3,848✔
5581
            // Covers the complete double range so can never overflow
5582
            return true;
5583
         }
5584
      }
5585
   }
5586

5587
   return false;
5588
}
5589

5590
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
34,562✔
5591
                              vcode_reg_t left, vcode_reg_t right,
5592
                              vcode_reg_t dir, vcode_reg_t locus,
5593
                              vcode_reg_t hint)
5594
{
5595
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
939,230✔
5596
      if (other->args.items[0] == reg && other->args.items[1] == left
10,883✔
5597
          && other->args.items[2] == right && other->args.items[3] == dir)
208✔
5598
         return;
5599
   }
5600

5601
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
34,354✔
5602
      emit_comment("Elided bounds check for r%d", reg);
22,968✔
5603
      return;
22,968✔
5604
   }
5605

5606
   op_t *op = vcode_add_op(kind);
11,386✔
5607
   vcode_add_arg(op, reg);
11,386✔
5608
   vcode_add_arg(op, left);
11,386✔
5609
   vcode_add_arg(op, right);
11,386✔
5610
   vcode_add_arg(op, dir);
11,386✔
5611
   vcode_add_arg(op, locus);
11,386✔
5612
   vcode_add_arg(op, hint);
11,386✔
5613

5614
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
11,386✔
5615
                "locus argument to bounds check must be a debug locus");
5616
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
11,386✔
5617
                "hint argument to bounds check must be a debug locus");
5618
}
5619

5620
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
2,609✔
5621
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5622
{
5623
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
2,609✔
5624
}
2,609✔
5625

5626
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
31,953✔
5627
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5628
{
5629
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
31,953✔
5630
}
31,953✔
5631

5632
void emit_push_scope(vcode_reg_t locus, vcode_type_t type)
1,058✔
5633
{
5634
   op_t *op = vcode_add_op(VCODE_OP_PUSH_SCOPE);
1,058✔
5635
   vcode_add_arg(op, locus);
1,058✔
5636
   op->type = type;
1,058✔
5637

5638
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,058✔
5639
                "locus argument to push scope must be a debug locus");
5640
}
1,058✔
5641

5642
void emit_pop_scope(void)
1,058✔
5643
{
5644
   vcode_add_op(VCODE_OP_POP_SCOPE);
1,058✔
5645
}
1,058✔
5646

5647
vcode_reg_t emit_debug_locus(ident_t unit, ptrdiff_t offset)
84,026✔
5648
{
5649
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
2,853,730✔
5650
      if (other->ident == unit && other->tag == offset)
320,545✔
5651
         return other->result;
4,209✔
5652
   }
5653

5654
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
79,817✔
5655
   op->ident = unit;
79,817✔
5656
   op->value = offset;
79,817✔
5657

5658
   return (op->result = vcode_add_reg(vtype_debug_locus()));
79,817✔
5659
}
5660

5661
void emit_debug_out(vcode_reg_t reg)
×
5662
{
5663
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
5664
   vcode_add_arg(op, reg);
×
5665
}
×
5666

5667
void emit_cover_stmt(uint32_t tag)
715✔
5668
{
5669
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
715✔
5670
   op->tag = tag;
715✔
5671
}
715✔
5672

5673
void emit_cover_branch(vcode_reg_t test, uint32_t tag, uint32_t flags)
308✔
5674
{
5675
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
308✔
5676
   vcode_add_arg(op, test);
308✔
5677
   op->tag = tag;
308✔
5678
   op->subkind = flags;
308✔
5679
}
308✔
5680

5681
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
281✔
5682
{
5683
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
281✔
5684
   vcode_add_arg(op, signal);
281✔
5685
   op->tag = tag;
281✔
5686
}
281✔
5687

5688
void emit_cover_expr(vcode_reg_t new_mask, uint32_t tag)
318✔
5689
{
5690
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
318✔
5691
   vcode_add_arg(op, new_mask);
318✔
5692
   op->tag = tag;
318✔
5693
}
318✔
5694

5695
void emit_unreachable(vcode_reg_t locus)
153✔
5696
{
5697
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
153✔
5698
   if (locus != VCODE_INVALID_REG)
153✔
5699
      vcode_add_arg(op, locus);
105✔
5700
}
153✔
5701

5702
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
1,290✔
5703
{
5704
   active_unit->flags |= UNIT_UNDEFINED;
1,290✔
5705

5706
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
1,290✔
5707
   op->result = vcode_add_reg(type);
1,290✔
5708
   vcode_reg_data(op->result)->bounds = bounds;
1,290✔
5709

5710
   return op->result;
1,290✔
5711
}
5712

5713
void emit_debug_info(const loc_t *loc)
1,491,920✔
5714
{
5715
   if (!loc_invalid_p(loc))
1,491,920✔
5716
      vcode_block_data()->last_loc = *loc;
1,417,910✔
5717
}
1,491,920✔
5718

5719
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
3,750✔
5720
{
5721
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
131,383✔
5722
      if (other->args.items[0] == context && other->ident == name)
5,773✔
5723
         return other->result;
1,250✔
5724
   }
5725

5726
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
2,500✔
5727
   vcode_add_arg(op, context);
2,500✔
5728
   op->ident = name;
2,500✔
5729

5730
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
2,500✔
5731
                "first argument to link var must be context");
5732

5733
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
2,500✔
5734
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
79✔
5735
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
79✔
5736
   }
5737
   else {
5738
      op->result = vcode_add_reg(vtype_pointer(type));
2,421✔
5739
      vcode_reg_data(op->result)->bounds = type;
2,421✔
5740
   }
5741

5742
   return op->result;
2,500✔
5743
}
5744

5745
vcode_reg_t emit_link_package(ident_t name)
18,729✔
5746
{
5747
   VCODE_FOR_EACH_OP(other) {
767,801✔
5748
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
757,905✔
5749
         return other->result;
5,470✔
5750
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
752,435✔
5751
         return other->result;
3,363✔
5752
   }
5753

5754
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
9,896✔
5755
   op->ident = name;
9,896✔
5756

5757
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
9,896✔
5758

5759
   return (op->result = vcode_add_reg(vtype_context(name)));
9,896✔
5760
}
5761

5762
vcode_reg_t emit_link_instance(ident_t name, vcode_reg_t locus)
108✔
5763
{
5764
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_INSTANCE) {
510✔
5765
      if (other->ident == name)
39✔
5766
         return other->result;
24✔
5767
   }
5768

5769
   op_t *op = vcode_add_op(VCODE_OP_LINK_INSTANCE);
84✔
5770
   vcode_add_arg(op, locus);
84✔
5771
   op->ident = name;
84✔
5772

5773
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
84✔
5774
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
84✔
5775
                "locus argument to link instance must be a debug locus");
5776

5777
   return (op->result = vcode_add_reg(vtype_context(name)));
84✔
5778
}
5779

5780
void emit_enter_state(vcode_reg_t state)
57✔
5781
{
5782
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
549✔
5783
      if (other->args.items[0] == state)
×
5784
         return;
5785
   }
5786

5787
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
57✔
5788
   vcode_add_arg(op, state);
57✔
5789

5790
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
57✔
5791
                "state must have integer type");
5792
}
5793

5794
vcode_reg_t emit_reflect_value(ident_t ptype, vcode_reg_t value,
45✔
5795
                               vcode_reg_t context, vcode_reg_t locus,
5796
                               vcode_reg_t bounds)
5797
{
5798
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
45✔
5799
   vcode_add_arg(op, value);
45✔
5800
   vcode_add_arg(op, context);
45✔
5801
   vcode_add_arg(op, locus);
45✔
5802
   if (bounds != VCODE_INVALID_REG)
45✔
5803
      vcode_add_arg(op, bounds);
6✔
5804

5805
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
45✔
5806
                "invalid reflect value context argument");
5807
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5808
                "locus argument to reflect value must be a debug locus");
5809

5810
   return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype))));
45✔
5811
}
5812

5813
vcode_reg_t emit_reflect_subtype(ident_t ptype, vcode_reg_t context,
42✔
5814
                                 vcode_reg_t locus, vcode_reg_t bounds)
5815
{
5816
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
5817
   vcode_add_arg(op, context);
42✔
5818
   vcode_add_arg(op, locus);
42✔
5819
   if (bounds != VCODE_INVALID_REG)
42✔
5820
      vcode_add_arg(op, bounds);
×
5821

5822
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
5823
                "invalid reflect value context argument");
5824
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
5825
                "locus argument to reflect value must be a debug locus");
5826

5827
   return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype))));
42✔
5828
}
5829

5830
vcode_reg_t emit_function_trigger(vcode_reg_t closure)
12✔
5831
{
5832
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
12✔
5833
   vcode_add_arg(op, closure);
12✔
5834

5835
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
12✔
5836
                "argument to function trigger must be a closure");
5837

5838
   return (op->result = vcode_add_reg(vtype_trigger()));
12✔
5839
}
5840

5841
void emit_add_trigger(vcode_reg_t trigger)
48✔
5842
{
5843
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
48✔
5844
   vcode_add_arg(op, trigger);
48✔
5845

5846
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
48✔
5847
                "add trigger argument must be trigger");
5848
}
48✔
5849

5850
static void vcode_write_unit(vcode_unit_t unit, fbuf_t *f,
×
5851
                             ident_wr_ctx_t ident_wr_ctx,
5852
                             loc_wr_ctx_t *loc_wr_ctx)
5853
{
5854
   write_u8(unit->kind, f);
×
5855
   ident_write(unit->name, ident_wr_ctx);
×
5856
   fbuf_put_int(f, unit->result);
×
5857
   fbuf_put_int(f, unit->flags);
×
5858
   fbuf_put_int(f, unit->depth);
×
5859

5860
   if (unit->offset < 0) {
×
5861
      object_t *obj = object_from_locus(unit->module, unit->offset, NULL);
×
5862
      object_locus(obj, &unit->module, &unit->offset);
×
5863
   }
5864

5865
   ident_write(unit->module, ident_wr_ctx);
×
5866
   fbuf_put_uint(f, unit->offset);
×
5867

5868
   if (unit->context != NULL) {
×
5869
      vcode_select_unit(unit);
×
5870
      vcode_select_unit(vcode_unit_context());
×
5871
      ident_write(vcode_unit_name(), ident_wr_ctx);
×
5872
      vcode_close();
×
5873
   }
5874
   else
5875
      ident_write(NULL, ident_wr_ctx);
×
5876

5877
   fbuf_put_uint(f, unit->blocks.count);
×
5878
   for (unsigned i = 0; i < unit->blocks.count; i++) {
×
5879
      const block_t *b = &(unit->blocks.items[i]);
×
5880
      fbuf_put_uint(f, b->ops.count);
×
5881

5882
      for (unsigned j = 0; j < b->ops.count; j++) {
×
5883
         op_t *op = &(b->ops.items[j]);
×
5884

5885
         if (op->kind == VCODE_OP_DEBUG_LOCUS)
×
5886
            object_fixup_locus(op->ident, &op->value);
×
5887

5888
         fbuf_put_uint(f, op->kind);
×
5889
         fbuf_put_uint(f, op->result);
×
5890
         loc_write(&(op->loc), loc_wr_ctx);
×
5891

5892
         fbuf_put_uint(f, op->args.count);
×
5893
         for (unsigned k = 0; k < op->args.count; k++)
×
5894
            fbuf_put_uint(f, op->args.items[k]);
×
5895

5896
         if (OP_HAS_TARGET(op->kind)) {
×
5897
            fbuf_put_uint(f, op->targets.count);
×
5898
            for (unsigned k = 0; k < op->targets.count; k++)
×
5899
               fbuf_put_uint(f, op->targets.items[k]);
×
5900
         }
5901

5902
         if (OP_HAS_TYPE(op->kind))
×
5903
            fbuf_put_uint(f, op->type);
×
5904
         if (OP_HAS_ADDRESS(op->kind))
×
5905
            fbuf_put_uint(f, op->address);
×
5906
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
×
5907
            ident_write(op->func, ident_wr_ctx);
×
5908
         if (OP_HAS_SUBKIND(op->kind))
×
5909
            fbuf_put_uint(f, op->subkind);
×
5910
         if (OP_HAS_CMP(op->kind))
×
5911
            fbuf_put_uint(f, op->cmp);
×
5912
         if (OP_HAS_VALUE(op->kind))
×
5913
            fbuf_put_int(f, op->value);
×
5914
         if (OP_HAS_REAL(op->kind))
×
5915
            write_double(op->real, f);
×
5916
         if (OP_HAS_COMMENT(op->kind))
×
5917
            ;   // Do not save comments
5918
         if (OP_HAS_DIM(op->kind))
×
5919
            fbuf_put_uint(f, op->dim);
×
5920
         if (OP_HAS_HOPS(op->kind))
×
5921
            fbuf_put_uint(f, op->hops);
×
5922
         if (OP_HAS_FIELD(op->kind))
×
5923
            fbuf_put_uint(f, op->field);
×
5924
         if (OP_HAS_TAG(op->kind))
×
5925
            fbuf_put_uint(f, op->tag);
×
5926
      }
5927
   }
5928

5929
   fbuf_put_uint(f, unit->regs.count);
×
5930
   for (unsigned i = 0; i < unit->regs.count; i++) {
×
5931
      const reg_t *r = &(unit->regs.items[i]);
×
5932
      fbuf_put_uint(f, r->type);
×
5933
      fbuf_put_uint(f, r->bounds);
×
5934
   }
5935

5936
   fbuf_put_uint(f, unit->types.count);
×
5937
   for (unsigned i = 0; i < unit->types.count; i++) {
×
5938
      const vtype_t *t = &(unit->types.items[i]);
×
5939
      fbuf_put_uint(f, t->kind);
×
5940
      switch (t->kind) {
×
5941
      case VCODE_TYPE_INT:
×
5942
      case VCODE_TYPE_OFFSET:
5943
         fbuf_put_int(f, t->repr);
×
5944
         fbuf_put_int(f, t->low);
×
5945
         fbuf_put_int(f, t->high);
×
5946
         break;
×
5947

5948
      case VCODE_TYPE_REAL:
×
5949
         write_double(t->rlow, f);
×
5950
         write_double(t->rhigh, f);
×
5951
         break;
×
5952

5953
      case VCODE_TYPE_CARRAY:
×
5954
      case VCODE_TYPE_UARRAY:
5955
         fbuf_put_uint(f, t->dims);
×
5956
         fbuf_put_uint(f, t->size);
×
5957
         fbuf_put_uint(f, t->elem);
×
5958
         fbuf_put_uint(f, t->bounds);
×
5959
         break;
×
5960

5961
      case VCODE_TYPE_ACCESS:
×
5962
      case VCODE_TYPE_POINTER:
5963
         fbuf_put_uint(f, t->pointed);
×
5964
         break;
×
5965

5966
      case VCODE_TYPE_FILE:
×
5967
      case VCODE_TYPE_SIGNAL:
5968
      case VCODE_TYPE_RESOLUTION:
5969
      case VCODE_TYPE_CLOSURE:
5970
         fbuf_put_uint(f, t->base);
×
5971
         break;
×
5972

5973
      case VCODE_TYPE_OPAQUE:
5974
      case VCODE_TYPE_DEBUG_LOCUS:
5975
      case VCODE_TYPE_TRIGGER:
5976
         break;
5977

5978
      case VCODE_TYPE_CONTEXT:
×
5979
         ident_write(t->name, ident_wr_ctx);
×
5980
         break;
×
5981

5982
      case VCODE_TYPE_RECORD:
×
5983
         ident_write(t->name, ident_wr_ctx);
×
5984
         fbuf_put_uint(f, t->fields.count);
×
5985
         for (unsigned j = 0; j < t->fields.count; j++)
×
5986
            fbuf_put_uint(f, t->fields.items[j]);
×
5987
         break;
5988
      }
5989
   }
×
5990

5991
   fbuf_put_uint(f, unit->vars.count);
×
5992
   for (unsigned i = 0; i < unit->vars.count; i++) {
×
5993
      const var_t *v = &(unit->vars.items[i]);
×
5994
      fbuf_put_uint(f, v->type);
×
5995
      fbuf_put_uint(f, v->bounds);
×
5996
      ident_write(v->name, ident_wr_ctx);
×
5997
      fbuf_put_uint(f, v->flags);
×
5998
   }
5999

6000
   fbuf_put_uint(f, unit->params.count);
×
6001
   for (unsigned i = 0; i < unit->params.count; i++) {
×
6002
      const param_t *p = &(unit->params.items[i]);
×
6003
      fbuf_put_uint(f, p->type);
×
6004
      fbuf_put_uint(f, p->bounds);
×
6005
      ident_write(p->name, ident_wr_ctx);
×
6006
      fbuf_put_uint(f, p->reg);
×
6007
   }
6008

6009
   if (unit->next != NULL)
×
6010
      vcode_write_unit(unit->next, f, ident_wr_ctx, loc_wr_ctx);
×
6011

6012
   if (unit->children != NULL)
×
6013
      vcode_write_unit(unit->children, f, ident_wr_ctx, loc_wr_ctx);
6014
}
×
6015

6016
void vcode_write(vcode_unit_t unit, fbuf_t *f, ident_wr_ctx_t ident_ctx,
×
6017
                 loc_wr_ctx_t *loc_ctx)
6018
{
6019
   assert(unit->context == NULL);
×
6020

6021
   write_u8(VCODE_VERSION, f);
×
6022

6023
   vcode_write_unit(unit, f, ident_ctx, loc_ctx);
×
6024
   write_u8(0xff, f);  // End marker
×
6025
}
×
6026

6027
static vcode_unit_t vcode_read_unit(fbuf_t *f, ident_rd_ctx_t ident_rd_ctx,
×
6028
                                    loc_rd_ctx_t *loc_rd_ctx, hash_t *seen)
6029
{
6030
   const uint8_t marker = read_u8(f);
×
6031
   if (marker == 0xff)
×
6032
      return false;
6033

6034
   vcode_unit_t unit = xcalloc(sizeof(struct _vcode_unit));
×
6035
   unit->kind   = marker;
×
6036
   unit->name   = ident_read(ident_rd_ctx);
×
6037
   unit->result = fbuf_get_int(f);
×
6038
   unit->flags  = fbuf_get_int(f);
×
6039
   unit->depth  = fbuf_get_int(f);
×
6040
   unit->module = ident_read(ident_rd_ctx);
×
6041
   unit->offset = fbuf_get_uint(f);
×
6042

6043
   hash_put(seen, unit->name, unit);
×
6044

6045
   ident_t context_name = ident_read(ident_rd_ctx);
×
6046
   if (context_name != NULL) {
×
6047
      unit->context = hash_get(seen, context_name);
×
6048
      if (unit->context == NULL)
×
6049
         fatal("%s references nonexistent context %s", fbuf_file_name(f),
×
6050
               istr(context_name));
6051

6052
      vcode_add_child(unit->context, unit);
×
6053
   }
6054
   else
6055
      unit->context = NULL;
×
6056

6057
   block_array_resize(&(unit->blocks), fbuf_get_uint(f), 0);
×
6058
   for (unsigned i = 0; i < unit->blocks.count; i++) {
×
6059
      block_t *b = &(unit->blocks.items[i]);
×
6060
      op_array_resize(&(b->ops), fbuf_get_uint(f), 0);
×
6061

6062
      for (unsigned j = 0; j < b->ops.count; j++) {
×
6063
         op_t *op = &(b->ops.items[j]);
×
6064

6065
         op->kind = fbuf_get_uint(f);
×
6066
         op->result = fbuf_get_uint(f);
×
6067
         loc_read(&(op->loc), loc_rd_ctx);
×
6068

6069
         vcode_reg_array_resize(&(op->args), fbuf_get_uint(f), 0);
×
6070
         for (unsigned k = 0; k < op->args.count; k++)
×
6071
            op->args.items[k] = fbuf_get_uint(f);
×
6072

6073
         if (OP_HAS_TARGET(op->kind)) {
×
6074
            vcode_block_array_resize(&(op->targets), fbuf_get_uint(f), 0);
×
6075
            for (unsigned k = 0; k < op->targets.count; k++)
×
6076
               op->targets.items[k] = fbuf_get_uint(f);
×
6077
         }
6078

6079
         if (OP_HAS_TYPE(op->kind))
×
6080
            op->type = fbuf_get_uint(f);
×
6081
         if (OP_HAS_ADDRESS(op->kind))
×
6082
            op->address = fbuf_get_uint(f);
×
6083
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
×
6084
            op->func = ident_read(ident_rd_ctx);
×
6085
         if (OP_HAS_SUBKIND(op->kind))
×
6086
            op->subkind = fbuf_get_uint(f);
×
6087
         if (OP_HAS_CMP(op->kind))
×
6088
            op->cmp = fbuf_get_uint(f);
×
6089
         if (OP_HAS_VALUE(op->kind))
×
6090
            op->value = fbuf_get_int(f);
×
6091
         if (OP_HAS_REAL(op->kind))
×
6092
            op->real = read_double(f);
×
6093
         if (OP_HAS_COMMENT(op->kind))
×
6094
            op->comment = NULL;
×
6095
         if (OP_HAS_DIM(op->kind))
×
6096
            op->dim = fbuf_get_uint(f);
×
6097
         if (OP_HAS_HOPS(op->kind))
×
6098
            op->hops = fbuf_get_uint(f);
×
6099
         if (OP_HAS_FIELD(op->kind))
×
6100
            op->field = fbuf_get_uint(f);
×
6101
         if (OP_HAS_TAG(op->kind))
×
6102
            op->tag = fbuf_get_uint(f);
×
6103
      }
6104
   }
6105

6106
   reg_array_resize(&(unit->regs), fbuf_get_uint(f), 0);
×
6107
   for (unsigned i = 0; i < unit->regs.count; i++) {
×
6108
      reg_t *r = &(unit->regs.items[i]);
×
6109
      r->type = fbuf_get_uint(f);
×
6110
      r->bounds = fbuf_get_uint(f);
×
6111
   }
6112

6113
   vtype_array_resize(&(unit->types), fbuf_get_uint(f), 0);
×
6114
   for (unsigned i = 0; i < unit->types.count; i++) {
×
6115
      vtype_t *t = &(unit->types.items[i]);
×
6116
      switch ((t->kind = fbuf_get_uint(f))) {
×
6117
      case VCODE_TYPE_INT:
×
6118
      case VCODE_TYPE_OFFSET:
6119
         t->repr = fbuf_get_int(f);
×
6120
         t->low = fbuf_get_int(f);
×
6121
         t->high = fbuf_get_int(f);
×
6122
         break;
×
6123

6124
      case VCODE_TYPE_REAL:
×
6125
         t->rlow = read_double(f);
×
6126
         t->rhigh = read_double(f);
×
6127
         break;
×
6128

6129
      case VCODE_TYPE_CARRAY:
×
6130
      case VCODE_TYPE_UARRAY:
6131
         t->dims = fbuf_get_uint(f);
×
6132
         t->size = fbuf_get_uint(f);
×
6133
         t->elem = fbuf_get_uint(f);
×
6134
         t->bounds = fbuf_get_uint(f);
×
6135
         break;
×
6136

6137
      case VCODE_TYPE_POINTER:
×
6138
      case VCODE_TYPE_ACCESS:
6139
         t->base = fbuf_get_uint(f);
×
6140
         break;
×
6141

6142
      case VCODE_TYPE_FILE:
×
6143
      case VCODE_TYPE_SIGNAL:
6144
      case VCODE_TYPE_RESOLUTION:
6145
      case VCODE_TYPE_CLOSURE:
6146
         t->base = fbuf_get_uint(f);
×
6147
         break;
×
6148

6149
      case VCODE_TYPE_OPAQUE:
6150
      case VCODE_TYPE_DEBUG_LOCUS:
6151
      case VCODE_TYPE_TRIGGER:
6152
         break;
6153

6154
      case VCODE_TYPE_CONTEXT:
×
6155
         t->name = ident_read(ident_rd_ctx);
×
6156
         break;
×
6157

6158
      case VCODE_TYPE_RECORD:
×
6159
         {
6160
            t->name = ident_read(ident_rd_ctx);
×
6161
            vcode_type_array_resize(&(t->fields), fbuf_get_uint(f), 0);
×
6162
            for (unsigned j = 0; j < t->fields.count; j++)
×
6163
               t->fields.items[j] = fbuf_get_uint(f);
×
6164
            break;
6165
         }
6166
      }
6167
   }
×
6168

6169
   var_array_resize(&(unit->vars), fbuf_get_uint(f), 0);
×
6170
   for (unsigned i = 0; i < unit->vars.count; i++) {
×
6171
      var_t *v = &(unit->vars.items[i]);
×
6172
      v->type = fbuf_get_uint(f);
×
6173
      v->bounds = fbuf_get_uint(f);
×
6174
      v->name = ident_read(ident_rd_ctx);
×
6175
      v->flags = fbuf_get_uint(f);
×
6176
   }
6177

6178
   param_array_resize(&(unit->params), fbuf_get_uint(f), 0);
×
6179
   for (unsigned i = 0; i < unit->params.count; i++) {
×
6180
      param_t *p = &(unit->params.items[i]);
×
6181
      p->type = fbuf_get_uint(f);
×
6182
      p->bounds = fbuf_get_uint(f);
×
6183
      p->name = ident_read(ident_rd_ctx);
×
6184
      p->reg = fbuf_get_uint(f);
×
6185
   }
6186

6187
   return unit;
6188
}
6189

6190
vcode_unit_t vcode_read(fbuf_t *f, ident_rd_ctx_t ident_ctx,
×
6191
                        loc_rd_ctx_t *loc_ctx)
6192
{
6193
   const uint8_t version = read_u8(f);
×
6194
   if (version != VCODE_VERSION) {
×
6195
      diag_t *d = diag_new(DIAG_FATAL, NULL);
×
6196
      diag_printf(d, "%s was created with vcode format version %d "
×
6197
                  "(expected %d)", fbuf_file_name(f), version, VCODE_VERSION);
6198
      diag_hint(d, NULL, "this file was most likely created with an earlier "
×
6199
                "version of " PACKAGE_NAME " and should be reanalysed");
6200
      diag_emit(d);
×
6201
      fatal_exit(EXIT_FAILURE);
×
6202
   }
6203

6204
   hash_t *seen = hash_new(128);
×
6205

6206
   vcode_unit_t vu, root = NULL;
×
6207
   while ((vu = vcode_read_unit(f, ident_ctx, loc_ctx, seen))) {
×
6208
      if (root == NULL)
×
6209
         root = vu;
×
6210
   }
6211

6212
   hash_free(seen);
×
6213
   return root;
×
6214
}
6215

6216
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
28,915✔
6217
{
6218
   vcode_select_unit(vu);
28,915✔
6219

6220
   const int nblocks = vcode_count_blocks();
28,915✔
6221
   for (int i = 0; i < nblocks; i++) {
146,480✔
6222
      vcode_select_block(i);
117,565✔
6223

6224
      const int nops = vcode_count_ops();
117,565✔
6225
      for (int op = 0; op < nops; op++) {
1,513,640✔
6226
         switch (vcode_get_op(op)) {
1,396,080✔
6227
         case VCODE_OP_LINK_PACKAGE:
12,435✔
6228
            (*fn)(vcode_get_ident(op), ctx);
12,435✔
6229
            break;
12,435✔
6230
         case VCODE_OP_FCALL:
50,415✔
6231
         case VCODE_OP_PCALL:
6232
         case VCODE_OP_CLOSURE:
6233
         case VCODE_OP_PROTECTED_INIT:
6234
         case VCODE_OP_PACKAGE_INIT:
6235
            {
6236
               const vcode_cc_t cc = vcode_get_subkind(op);
50,415✔
6237
               if (cc != VCODE_CC_FOREIGN && cc != VCODE_CC_VARIADIC)
50,415✔
6238
                  (*fn)(vcode_get_func(op), ctx);
49,384✔
6239
            }
6240
            break;
6241
         default:
6242
            break;
6243
         }
6244
      }
6245
   }
6246
}
28,915✔
6247

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

6256
__attribute__((constructor))
6257
static void vcode_check_unions(void)
6258
{
6259
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6260
   for (int i = 0; i < 256; i++) {
6261
      assert(OP_USE_COUNT_U0(i) <= 1);
6262
      assert(OP_USE_COUNT_U1(i) <= 1);
6263
   }
6264
}
6265
#endif  // VCODE_CHECK_UNIONS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc