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

nickg / nvc / 6535337722

16 Oct 2023 02:45PM UTC coverage: 91.176% (+0.009%) from 91.167%
6535337722

push

github

nickg
Add configure check for gettid. Fixes #774

49047 of 53794 relevant lines covered (91.18%)

585902.76 hits per line

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

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

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

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

35
DECLARE_AND_DEFINE_ARRAY(vcode_reg);
5,020,549✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
205,826✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
38,528✔
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,414,690✔
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);
26,037✔
162
DECLARE_AND_DEFINE_ARRAY(var);
37,181✔
163
DECLARE_AND_DEFINE_ARRAY(reg);
1,143,840✔
164
DECLARE_AND_DEFINE_ARRAY(block);
114,731✔
165
DECLARE_AND_DEFINE_ARRAY(vtype);
2,187,900✔
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,642✔
220
{
221
   int64_t result;
24,642✔
222
   if (__builtin_add_overflow(a, b, &result))
24,642✔
223
      return b < 0 ? INT64_MIN : INT64_MAX;
8,611✔
224

225
   return result;
226
}
227

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

234
   return result;
235
}
236

237
static inline int64_t smul64(int64_t a, int64_t b)
7,568✔
238
{
239
   int64_t result;
7,568✔
240
   if (__builtin_mul_overflow(a, b, &result))
7,568✔
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,143,840✔
247
{
248
   assert(active_unit != NULL);
1,143,840✔
249

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

256
   return reg;
1,143,840✔
257
}
258

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

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

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

275
   block_t *block = vcode_block_data();
1,414,690✔
276

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

283
   return op;
1,414,690✔
284
}
285

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

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

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

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

305
static op_t *vcode_find_definition(vcode_reg_t reg)
1,194,280✔
306
{
307
   for (int i = active_block; i >= 0; i--) {
1,241,200✔
308
      block_t *b = &(active_unit->blocks.items[i]);
1,238,370✔
309
      for (int j = b->ops.count - 1; j >= 0; j--) {
22,784,000✔
310
         if (b->ops.items[j].result == reg)
22,737,100✔
311
            return &(b->ops.items[j]);
1,191,450✔
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,162,060✔
320
{
321
   op_t *defn = vcode_find_definition(reg);
1,162,060✔
322
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
1,162,060✔
323
                what, reg);
324
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
1,162,060✔
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,162,060✔
333
#endif
334

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

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

348
   int depth = MASK_CONTEXT(type);
61,881,700✔
349
   assert(depth <= unit->depth);
61,881,700✔
350
   while (depth != unit->depth)
62,787,100✔
351
      unit = unit->context;
905,403✔
352

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

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

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

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

372
   switch (defn->kind) {
29,388✔
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
   case VCODE_OP_PACKAGE_INIT:
384
      break;
385

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

596
vcode_type_t vcode_reg_type(vcode_reg_t reg)
4,130,930✔
597
{
598
   return vcode_reg_data(reg)->type;
4,130,930✔
599
}
600

601
vtype_kind_t vcode_reg_kind(vcode_reg_t reg)
1,098,810✔
602
{
603
   return vtype_kind(vcode_reg_type(reg));
1,098,810✔
604
}
605

606
vcode_type_t vcode_reg_bounds(vcode_reg_t reg)
180,445✔
607
{
608
   return vcode_reg_data(reg)->bounds;
180,445✔
609
}
610

611
bool vcode_reg_const(vcode_reg_t reg, int64_t *value)
730,540✔
612
{
613
   reg_t *r = vcode_reg_data(reg);
730,540✔
614

615
   vtype_kind_t kind = vtype_kind(r->type);
730,540✔
616
   if (kind != VCODE_TYPE_INT && kind != VCODE_TYPE_OFFSET)
730,540✔
617
      return false;
618

619
   vtype_t *bounds = vcode_type_data(r->bounds);
715,353✔
620

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

625
   if (bounds->low == bounds->high) {
715,353✔
626
      if (value) *value = bounds->low;
449,533✔
627
      return true;
449,533✔
628
   }
629
   else
630
      return false;
631
}
632

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

637
   int *uses LOCAL = xmalloc_array(active_unit->regs.count, sizeof(int));
70,356✔
638

639
   int pruned = 0;
35,178✔
640
   do {
54,869✔
641
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
54,869✔
642
      pruned = 0;
54,869✔
643

644
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
260,135✔
645
         block_t *b = &(active_unit->blocks.items[i]);
205,266✔
646

647
         for (int j = b->ops.count - 1; j >= 0; j--) {
2,862,860✔
648
            op_t *o = &(b->ops.items[j]);
2,657,600✔
649

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

709
            default:
710
               break;
711
            }
712

713
            for (int k = 0; k < o->args.count; k++) {
7,243,800✔
714
               if (o->args.items[k] != VCODE_INVALID_REG)
4,586,200✔
715
                  uses[o->args.items[k]]++;
4,539,430✔
716
            }
717
         }
718
      }
719
   } while (pruned > 0);
54,869✔
720

721
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
149,909✔
722
      block_t *b = &(active_unit->blocks.items[i]);
114,731✔
723
      op_t *dst = &(b->ops.items[0]);
114,731✔
724
      size_t copied = 0;
114,731✔
725
      for (int j = 0; j < b->ops.count; j++) {
1,529,420✔
726
         const op_t *src = &(b->ops.items[j]);
1,414,690✔
727
         if (src->kind != (vcode_op_t)-1) {
1,414,690✔
728
            if (src != dst) {
1,293,700✔
729
               assert(dst < src);
493,626✔
730
               *dst = *src;
493,626✔
731
            }
732
            dst++;
1,293,700✔
733
            copied++;
1,293,700✔
734
         }
735
      }
736

737
      assert(copied <= b->ops.count);
114,731✔
738
      b->ops.count = copied;
114,731✔
739
   }
740
}
35,178✔
741

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

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

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

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

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

775
   return VCODE_INVALID_VAR;
776
}
777

778
ident_t vcode_var_name(vcode_var_t var)
28,910✔
779
{
780
   return vcode_var_data(var)->name;
28,910✔
781
}
782

783
vcode_type_t vcode_var_type(vcode_var_t var)
118,350✔
784
{
785
   return vcode_var_data(var)->type;
118,350✔
786
}
787

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

793
vcode_var_flags_t vcode_var_flags(vcode_var_t var)
30,614✔
794
{
795
   return vcode_var_data(var)->flags;
30,614✔
796
}
797

798
vcode_op_t vcode_get_op(int op)
4,008,260✔
799
{
800
   return vcode_op_data(op)->kind;
4,008,260✔
801
}
802

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

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

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

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

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

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

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

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

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

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

873
int vcode_count_args(int op)
162,284✔
874
{
875
   return vcode_op_data(op)->args.count;
162,284✔
876
}
877

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

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

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

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

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

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

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

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

925
bool vcode_block_finished(void)
1,509,320✔
926
{
927
   assert(active_unit != NULL);
1,509,320✔
928
   assert(active_block != VCODE_INVALID_BLOCK);
1,509,320✔
929

930
   const block_t *b = &(active_unit->blocks.items[active_block]);
1,509,320✔
931
   if (b->ops.count == 0)
1,509,320✔
932
      return false;
933
   else {
934
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,354,820✔
935
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,354,820✔
936
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,354,800✔
937
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
1,354,800✔
938
         || kind == VCODE_OP_UNREACHABLE;
4,053,640✔
939
   }
940
}
941

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

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

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

987
   return printed;
988
}
989

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1114
   return col;
1115
}
1116

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

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

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

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

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

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

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

1169
   dump_callback = callback;
1170
   dump_arg = arg;
1171

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1847
         case VCODE_OP_UNWRAP:
1848
            {
1849
               col += vcode_dump_reg(op->result);
1850
               col += printf(" := %s ", vcode_op_string(op->kind));
1851
               col += vcode_dump_reg(op->args.items[0]);
1852
               vcode_dump_result_type(col, op);
1853
            }
1854
            break;
1855

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2302
         color_printf("$$\n");
2303

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

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

2312
   printf("\n");
2313
   fflush(stdout);
2314

2315
   active_block = old_block;
2316
}
2317
LCOV_EXCL_STOP
2318

2319
bool vtype_eq(vcode_type_t a, vcode_type_t b)
29,083,900✔
2320
{
2321
   assert(active_unit != NULL);
29,494,700✔
2322

2323
   if (a == b)
29,494,700✔
2324
      return true;
2325
   else {
2326
      const vtype_t *at = vcode_type_data(a);
27,055,000✔
2327
      const vtype_t *bt = vcode_type_data(b);
27,055,000✔
2328

2329
      if (at->kind != bt->kind)
27,055,000✔
2330
         return false;
2331

2332
      switch (at->kind) {
12,337,000✔
2333
      case VCODE_TYPE_INT:
10,536,700✔
2334
         return (at->low == bt->low) && (at->high == bt->high);
19,849,800✔
2335
      case VCODE_TYPE_REAL:
910,233✔
2336
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
1,772,270✔
2337
      case VCODE_TYPE_CARRAY:
80,729✔
2338
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
86,922✔
2339
      case VCODE_TYPE_UARRAY:
71,249✔
2340
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
86,080✔
2341
      case VCODE_TYPE_POINTER:
346,804✔
2342
      case VCODE_TYPE_ACCESS:
2343
         return vtype_eq(at->pointed, bt->pointed);
346,804✔
2344
      case VCODE_TYPE_OFFSET:
2345
      case VCODE_TYPE_OPAQUE:
2346
      case VCODE_TYPE_DEBUG_LOCUS:
2347
      case VCODE_TYPE_TRIGGER:
2348
         return true;
2349
      case VCODE_TYPE_RESOLUTION:
63,963✔
2350
      case VCODE_TYPE_CLOSURE:
2351
      case VCODE_TYPE_SIGNAL:
2352
      case VCODE_TYPE_FILE:
2353
         return vtype_eq(at->base, bt->base);
63,963✔
2354
      case VCODE_TYPE_RECORD:
56,391✔
2355
      case VCODE_TYPE_CONTEXT:
2356
         return at->name == bt->name;
56,391✔
2357
      }
2358

2359
      return false;
×
2360
   }
2361
}
2362

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

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

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

2381
   return type;
2382
}
2383

2384
vcode_type_t vtype_int(int64_t low, int64_t high)
1,477,840✔
2385
{
2386
   assert(active_unit != NULL);
1,477,840✔
2387

2388
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,477,840✔
2389
   n->kind = VCODE_TYPE_INT;
1,477,840✔
2390
   n->low  = low;
1,477,840✔
2391
   n->high = high;
1,477,840✔
2392

2393
   switch (bits_for_range(low, high)) {
1,477,840✔
2394
   case 64:
114,734✔
2395
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
114,734✔
2396
      break;
114,734✔
2397
   case 32:
343,328✔
2398
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
343,328✔
2399
      break;
343,328✔
2400
   case 16:
2,445✔
2401
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
2,445✔
2402
      break;
2,445✔
2403
   case 8:
423,441✔
2404
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
423,441✔
2405
      break;
423,441✔
2406
   case 1:
593,887✔
2407
      n->repr = VCODE_REPR_U1;
593,887✔
2408
      break;
593,887✔
2409
   default:
×
2410
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
×
2411
   }
2412

2413
   return vtype_new(n);
1,477,840✔
2414
}
2415

2416
vcode_type_t vtype_bool(void)
297,647✔
2417
{
2418
   return vtype_int(0, 1);
297,647✔
2419
}
2420

2421
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
35,521✔
2422
{
2423
   assert(active_unit != NULL);
35,521✔
2424

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

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

2436
   return vtype_new(n);
35,521✔
2437
}
2438

2439
vcode_type_t vtype_find_named_record(ident_t name)
24,599✔
2440
{
2441
   assert(active_unit != NULL);
24,599✔
2442

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

2449
   return VCODE_INVALID_TYPE;
2450
}
2451

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

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

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

2473
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
8,424✔
2474
   for (int i = 0; i < nfields; i++)
23,476✔
2475
      vcode_type_array_add(&(data->fields), field_types[i]);
15,052✔
2476

2477
   return handle;
8,424✔
2478
}
2479

2480
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
70,743✔
2481
{
2482
   assert(active_unit != NULL);
70,743✔
2483

2484
   const vtype_kind_t ekind = vtype_kind(elem);
70,743✔
2485
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
70,743✔
2486
                "array types may not be nested");
2487

2488
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
70,743✔
2489

2490
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
70,743✔
2491
   memset(n, '\0', sizeof(vtype_t));
70,743✔
2492
   n->kind   = VCODE_TYPE_UARRAY;
70,743✔
2493
   n->elem   = elem;
70,743✔
2494
   n->bounds = bounds;
70,743✔
2495
   n->dims   = ndim;
70,743✔
2496

2497
   return vtype_new(n);
70,743✔
2498
}
2499

2500
vcode_type_t vtype_pointer(vcode_type_t to)
144,557✔
2501
{
2502
   assert(active_unit != NULL);
144,557✔
2503

2504
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
144,557✔
2505
   n->kind    = VCODE_TYPE_POINTER;
144,557✔
2506
   n->pointed = to;
144,557✔
2507

2508
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
144,557✔
2509
                "cannot get pointer to carray type");
2510

2511
   return vtype_new(n);
144,557✔
2512
}
2513

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

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

2522
   return vtype_new(n);
4,386✔
2523
}
2524

2525
vcode_type_t vtype_signal(vcode_type_t base)
25,149✔
2526
{
2527
   assert(active_unit != NULL);
25,149✔
2528

2529
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
25,149✔
2530
   n->kind = VCODE_TYPE_SIGNAL;
25,149✔
2531
   n->base = base;
25,149✔
2532

2533
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
25,149✔
2534

2535
   return vtype_new(n);
25,149✔
2536
}
2537

2538
vcode_type_t vtype_resolution(vcode_type_t base)
563✔
2539
{
2540
   assert(active_unit != NULL);
563✔
2541

2542
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
563✔
2543
   n->kind = VCODE_TYPE_RESOLUTION;
563✔
2544
   n->base = base;
563✔
2545

2546
   return vtype_new(n);
563✔
2547
}
2548

2549
vcode_type_t vtype_closure(vcode_type_t result)
695✔
2550
{
2551
   assert(active_unit != NULL);
695✔
2552

2553
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
695✔
2554
   n->kind = VCODE_TYPE_CLOSURE;
695✔
2555
   n->base = result;
695✔
2556

2557
   return vtype_new(n);
695✔
2558
}
2559

2560
vcode_type_t vtype_context(ident_t name)
43,967✔
2561
{
2562
   assert(active_unit != NULL);
43,967✔
2563
   assert(name != NULL);
43,967✔
2564

2565
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
43,967✔
2566
   n->kind = VCODE_TYPE_CONTEXT;
43,967✔
2567
   n->name = name;
43,967✔
2568

2569
   return vtype_new(n);
43,967✔
2570
}
2571

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

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

2580
   return vtype_new(n);
337✔
2581
}
2582

2583
vcode_type_t vtype_offset(void)
220,375✔
2584
{
2585
   assert(active_unit != NULL);
220,375✔
2586

2587
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
220,375✔
2588
   n->kind = VCODE_TYPE_OFFSET;
220,375✔
2589
   n->low  = INT64_MIN;
220,375✔
2590
   n->high = INT64_MAX;
220,375✔
2591
   n->repr = VCODE_REPR_I64;
220,375✔
2592

2593
   return vtype_new(n);
220,375✔
2594
}
2595

2596
vcode_type_t vtype_time(void)
13,799✔
2597
{
2598
   return vtype_int(INT64_MIN, INT64_MAX);
13,799✔
2599
}
2600

2601
vcode_type_t vtype_char(void)
8,328✔
2602
{
2603
   return vtype_int(0, 255);
8,328✔
2604
}
2605

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

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

2613
   return vtype_new(n);
295✔
2614
}
2615

2616
vcode_type_t vtype_debug_locus(void)
84,193✔
2617
{
2618
   assert(active_unit != NULL);
84,193✔
2619

2620
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
84,193✔
2621
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
84,193✔
2622

2623
   return vtype_new(n);
84,193✔
2624
}
2625

2626
vcode_type_t vtype_trigger(void)
24✔
2627
{
2628
   assert(active_unit != NULL);
24✔
2629

2630
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
24✔
2631
   n->kind = VCODE_TYPE_TRIGGER;
24✔
2632

2633
   return vtype_new(n);
24✔
2634
}
2635

2636
vcode_type_t vtype_real(double low, double high)
75,041✔
2637
{
2638
   assert(active_unit != NULL);
75,041✔
2639

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

2645
   return vtype_new(n);
75,041✔
2646
}
2647

2648
vtype_kind_t vtype_kind(vcode_type_t type)
5,083,120✔
2649
{
2650
   vtype_t *vt = vcode_type_data(type);
5,083,120✔
2651
   return vt->kind;
5,083,120✔
2652
}
2653

2654
vtype_repr_t vtype_repr(vcode_type_t type)
408,338✔
2655
{
2656
   vtype_t *vt = vcode_type_data(type);
408,338✔
2657
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
408,338✔
2658
   return vt->repr;
408,338✔
2659
}
2660

2661
vcode_type_t vtype_elem(vcode_type_t type)
317,733✔
2662
{
2663
   vtype_t *vt = vcode_type_data(type);
317,733✔
2664
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
317,733✔
2665
   return vt->elem;
317,733✔
2666
}
2667

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

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

2684
unsigned vtype_dims(vcode_type_t type)
113,815✔
2685
{
2686
   vtype_t *vt = vcode_type_data(type);
113,815✔
2687
   assert(vt->kind == VCODE_TYPE_UARRAY);
113,815✔
2688
   return vt->dims;
113,815✔
2689
}
2690

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

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

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

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

2719
vcode_type_t vtype_pointed(vcode_type_t type)
275,833✔
2720
{
2721
   vtype_t *vt = vcode_type_data(type);
275,833✔
2722
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
275,833✔
2723
   return vt->pointed;
275,833✔
2724
}
2725

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

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

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

2746
bool vtype_is_scalar(vcode_type_t type)
282,612✔
2747
{
2748
   const vtype_kind_t kind = vtype_kind(type);
282,612✔
2749
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
282,612✔
2750
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
81,050✔
2751
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
60,192✔
2752
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
57,190✔
2753
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER;
284,009✔
2754
}
2755

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

2762
bool vtype_is_signal(vcode_type_t type)
144,805✔
2763
{
2764
   vtype_t *vt = vcode_type_data(type);
259,912✔
2765
   switch (vt->kind) {
259,912✔
2766
   case VCODE_TYPE_SIGNAL:
2767
      return true;
2768
   case VCODE_TYPE_POINTER:
60,915✔
2769
      return vtype_is_signal(vt->pointed);
60,915✔
2770
   case VCODE_TYPE_RECORD:
2771
      for (int i = 0; i < vt->fields.count; i++) {
29,013✔
2772
         if (vtype_is_signal(vt->fields.items[i]))
23,328✔
2773
            return true;
2774
      }
2775
      return false;
2776
   case VCODE_TYPE_UARRAY:
54,192✔
2777
   case VCODE_TYPE_CARRAY:
2778
      return vtype_is_signal(vt->elem);
54,192✔
2779
   default:
122,622✔
2780
      return false;
122,622✔
2781
   }
2782
}
2783

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

2796
bool vtype_repr_signed(vtype_repr_t repr)
40,695✔
2797
{
2798
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
40,695✔
2799
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
40,695✔
2800
}
2801

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

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

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

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

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

2856
   return active_unit->params.count;
9,323✔
2857
}
2858

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

2868
   return active_unit->params.items[param].type;
24,759✔
2869
}
2870

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

2880
   return active_unit->params.items[param].reg;
31,746✔
2881
}
2882

2883
vcode_block_t emit_block(void)
114,731✔
2884
{
2885
   assert(active_unit != NULL);
114,731✔
2886

2887
   vcode_block_t bnum = active_unit->blocks.count;
114,731✔
2888

2889
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
114,731✔
2890
   memset(bptr, '\0', sizeof(block_t));
114,731✔
2891

2892
   if (active_block != VCODE_INVALID_BLOCK)
114,731✔
2893
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
79,553✔
2894
   else
2895
      bptr->last_loc = LOC_INVALID;
35,178✔
2896

2897
   return bnum;
114,731✔
2898
}
2899

2900
void vcode_select_unit(vcode_unit_t unit)
312,521✔
2901
{
2902
   active_unit  = unit;
312,521✔
2903
   active_block = VCODE_INVALID_BLOCK;
312,521✔
2904
}
312,521✔
2905

2906
void vcode_select_block(vcode_block_t block)
512,482✔
2907
{
2908
   assert(active_unit != NULL);
512,482✔
2909
   active_block = block;
512,482✔
2910
}
512,482✔
2911

2912
vcode_block_t vcode_active_block(void)
1,242,340✔
2913
{
2914
   assert(active_unit != NULL);
1,242,340✔
2915
   assert(active_block != -1);
1,242,340✔
2916
   return active_block;
1,242,340✔
2917
}
2918

2919
const loc_t *vcode_last_loc(void)
713,173✔
2920
{
2921
   return &(vcode_block_data()->last_loc);
713,173✔
2922
}
2923

2924
vcode_unit_t vcode_active_unit(void)
40,790✔
2925
{
2926
   assert(active_unit != NULL);
40,790✔
2927
   return active_unit;
40,790✔
2928
}
2929

2930
ident_t vcode_unit_name(void)
234,134✔
2931
{
2932
   assert(active_unit != NULL);
234,134✔
2933
   return active_unit->name;
234,134✔
2934
}
2935

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

2942
bool vcode_unit_has_escaping_tlab(vcode_unit_t vu)
4,452✔
2943
{
2944
   return !!(vu->flags & UNIT_ESCAPING_TLAB);
4,452✔
2945
}
2946

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

2953
void vcode_set_result(vcode_type_t type)
17,833✔
2954
{
2955
   assert(active_unit != NULL);
17,833✔
2956
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
17,833✔
2957
          || active_unit->kind == VCODE_UNIT_THUNK);
2958

2959
   active_unit->result = type;
17,833✔
2960
}
17,833✔
2961

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

2970
vunit_kind_t vcode_unit_kind(void)
319,495✔
2971
{
2972
   assert(active_unit != NULL);
319,495✔
2973
   return active_unit->kind;
319,495✔
2974
}
2975

2976
vcode_unit_t vcode_unit_context(void)
98,406✔
2977
{
2978
   assert(active_unit != NULL);
98,406✔
2979
   return active_unit->context;
98,406✔
2980
}
2981

2982
void vcode_unit_object(vcode_unit_t vu, ident_t *module, ptrdiff_t *offset)
41,928✔
2983
{
2984
   assert(vu != NULL);
41,928✔
2985
   *module = vu->module;
41,928✔
2986
   *offset = vu->offset;
41,928✔
2987
}
41,928✔
2988

2989
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
44,916✔
2990
{
2991
   int hops = 0;
44,916✔
2992
   for (; (unit = unit->context); hops++)
91,331✔
2993
      ;
46,415✔
2994
   return hops;
44,916✔
2995
}
2996

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

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

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

3021
   object_locus(obj, &vu->module, &vu->offset);
9,148✔
3022

3023
   vcode_add_child(context, vu);
9,148✔
3024

3025
   vcode_select_unit(vu);
9,148✔
3026
   vcode_select_block(emit_block());
9,148✔
3027
   emit_debug_info(&(obj->loc));
9,148✔
3028

3029
   return vu;
9,148✔
3030
}
3031

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

3041
   object_locus(obj, &vu->module, &vu->offset);
407✔
3042

3043
   vcode_add_child(context, vu);
407✔
3044

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

3049
   return vu;
407✔
3050
}
3051

3052
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
7,384✔
3053
{
3054
   assert(context->kind == VCODE_UNIT_INSTANCE);
7,384✔
3055

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

3063
   object_locus(obj, &vu->module, &vu->offset);
7,384✔
3064

3065
   vcode_add_child(context, vu);
7,384✔
3066

3067
   vcode_select_unit(vu);
7,384✔
3068
   vcode_select_block(emit_block());
7,384✔
3069
   emit_debug_info(&(obj->loc));
7,384✔
3070

3071
   return vu;
7,384✔
3072
}
3073

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

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

3085
   object_locus(obj, &vu->module, &vu->offset);
6,887✔
3086

3087
   if (context != NULL)
6,887✔
3088
      vcode_add_child(context, vu);
3,997✔
3089

3090
   vcode_select_unit(vu);
6,887✔
3091
   vcode_select_block(emit_block());
6,887✔
3092
   emit_debug_info(&(obj->loc));
6,887✔
3093

3094
   return vu;
6,887✔
3095
}
3096

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

3106
   object_locus(obj, &vu->module, &vu->offset);
1,411✔
3107

3108
   if (context != NULL)
1,411✔
3109
      vcode_add_child(context, vu);
127✔
3110

3111
   vcode_select_unit(vu);
1,411✔
3112
   vcode_select_block(emit_block());
1,411✔
3113
   emit_debug_info(&(obj->loc));
1,411✔
3114

3115
   return vu;
1,411✔
3116
}
3117

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

3127
   object_locus(obj, &vu->module, &vu->offset);
155✔
3128

3129
   if (context != NULL)
155✔
3130
      vcode_add_child(context, vu);
155✔
3131

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

3136
   return vu;
155✔
3137
}
3138

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

3148
   object_locus(obj, &vu->module, &vu->offset);
48✔
3149

3150
   if (context != NULL)
48✔
3151
      vcode_add_child(context, vu);
48✔
3152

3153
   vcode_select_unit(vu);
48✔
3154
   vcode_select_block(emit_block());
48✔
3155
   emit_debug_info(&(obj->loc));
48✔
3156

3157
   return vu;
48✔
3158
}
3159

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

3170
   object_locus(obj, &vu->module, &vu->offset);
9,738✔
3171

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

3175
   vcode_select_unit(vu);
9,738✔
3176
   vcode_select_block(emit_block());
9,738✔
3177

3178
   return vu;
9,738✔
3179
}
3180

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

3191
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
12,840✔
3192
   vcode_add_arg(op, value);
12,840✔
3193
   vcode_add_arg(op, severity);
12,840✔
3194
   vcode_add_arg(op, message);
12,840✔
3195
   vcode_add_arg(op, length);
12,840✔
3196
   vcode_add_arg(op, locus);
12,840✔
3197

3198
   if (hint_left != VCODE_INVALID_REG) {
12,840✔
3199
      vcode_add_arg(op, hint_left);
5,054✔
3200
      vcode_add_arg(op, hint_right);
5,054✔
3201

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

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

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

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

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

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

3269
   // Reuse any previous operation in this block with the same arguments
3270
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
580,659✔
3271
      if (other->args.count == 2 && other->args.items[0] == lhs
25,986✔
3272
          && other->args.items[1] == rhs && other->cmp == cmp)
1,357✔
3273
         return other->result;
355✔
3274
   }
3275

3276
   op_t *op = vcode_add_op(VCODE_OP_CMP);
31,277✔
3277
   vcode_add_arg(op, lhs);
31,277✔
3278
   vcode_add_arg(op, rhs);
31,277✔
3279
   op->cmp    = cmp;
31,277✔
3280
   op->result = vcode_add_reg(vtype_bool());
31,277✔
3281

3282
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
31,277✔
3283
                "arguments to cmp are not the same type");
3284

3285
   return op->result;
3286
}
3287

3288
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_type_t bounds,
31,212✔
3289
                       vcode_cc_t cc, const vcode_reg_t *args, int nargs)
3290
{
3291
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
31,212✔
3292
   o->func    = func;
31,212✔
3293
   o->type    = type;
31,212✔
3294
   o->subkind = cc;
31,212✔
3295
   for (int i = 0; i < nargs; i++)
119,327✔
3296
      vcode_add_arg(o, args[i]);
88,115✔
3297

3298
   for (int i = 0; i < nargs; i++)
119,327✔
3299
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
88,115✔
3300
                   "invalid argument to function");
3301

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

3306
   if (type == VCODE_INVALID_TYPE)
31,212✔
3307
      return (o->result = VCODE_INVALID_REG);
3,267✔
3308
   else {
3309
      o->result = vcode_add_reg(type);
27,945✔
3310

3311
      reg_t *rr = vcode_reg_data(o->result);
27,945✔
3312
      rr->bounds = bounds;
27,945✔
3313

3314
      return o->result;
27,945✔
3315
   }
3316
}
3317

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

3327
   vcode_block_array_add(&(o->targets), resume_bb);
1,971✔
3328

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

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

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

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

3351
   reg_t *r = vcode_reg_data(op->result);
5,594✔
3352
   r->bounds = bounds;
5,594✔
3353

3354
   return op->result;
5,594✔
3355
}
3356

3357
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
1,027,080✔
3358
{
3359
   // Reuse any previous constant in this block with the same type and value
3360
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
30,266,900✔
3361
      if (other->kind == VCODE_OP_CONST && other->value == value
8,613,550✔
3362
          && vtype_eq(type, other->type))
915,141✔
3363
         return other->result;
607,959✔
3364
   }
3365

3366
   op_t *op = vcode_add_op(VCODE_OP_CONST);
419,120✔
3367
   op->value  = value;
419,120✔
3368
   op->type   = type;
419,120✔
3369
   op->result = vcode_add_reg(type);
419,120✔
3370

3371
   vtype_kind_t type_kind = vtype_kind(type);
419,120✔
3372
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
419,120✔
3373
                "constant must have integer or offset type");
3374

3375
   reg_t *r = vcode_reg_data(op->result);
419,120✔
3376
   r->bounds = vtype_int(value, value);
419,120✔
3377

3378
   return op->result;
419,120✔
3379
}
3380

3381
vcode_reg_t emit_const_real(vcode_type_t type, double value)
33,145✔
3382
{
3383
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
1,184,750✔
3384
      if (other->real == value && other->type == type)
849,268✔
3385
         return other->result;
9,656✔
3386
   }
3387

3388
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
23,489✔
3389
   op->real   = value;
23,489✔
3390
   op->type   = type;
23,489✔
3391
   op->result = vcode_add_reg(op->type);
23,489✔
3392

3393
   reg_t *r = vcode_reg_data(op->result);
23,489✔
3394
   r->bounds = vtype_real(value, value);
23,489✔
3395

3396
   return op->result;
23,489✔
3397
}
3398

3399
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
27,304✔
3400
{
3401
   vtype_kind_t kind = vtype_kind(type);
27,304✔
3402

3403
   // Reuse any previous operation in this block with the same arguments
3404
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,068,250✔
3405
      if (other->args.count != num)
103,493✔
3406
         continue;
57,877✔
3407
      else if (!vtype_eq(vcode_reg_type(other->result), type))
45,616✔
3408
         continue;
460✔
3409

3410
      bool match = true;
3411
      for (int i = 0; match && i < num; i++) {
284,269✔
3412
         if (other->args.items[i] != values[i])
239,113✔
3413
            match = false;
39,983✔
3414
      }
3415

3416
      if (match) return other->result;
45,156✔
3417
   }
3418

3419
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
22,131✔
3420
   op->result = vcode_add_reg(type);
22,131✔
3421

3422
   for (int i = 0; i < num; i++)
1,178,250✔
3423
      vcode_add_arg(op, values[i]);
1,156,120✔
3424

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

3430
#ifdef DEBUG
3431
   vcode_type_t elem = vtype_elem(type);
22,131✔
3432
   for (int i = 0; i < num; i++) {
1,178,250✔
3433
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,156,120✔
3434
                   "wrong element type for item %d", i);
3435
      vcode_assert_const(values[i], "array");
1,156,120✔
3436
   }
3437
#endif
3438

3439
   reg_t *r = vcode_reg_data(op->result);
22,131✔
3440
   r->bounds = vtype_elem(type);
22,131✔
3441

3442
   return op->result;
22,131✔
3443
}
3444

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

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

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

3460
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
656✔
3461

3462
   op->result = vcode_add_reg(type);
656✔
3463

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

3467
   return op->result;
656✔
3468
}
3469

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

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

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

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

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

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

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

3505
   return op->result;
1,764✔
3506
}
3507

3508
vcode_reg_t emit_address_of(vcode_reg_t value)
28,762✔
3509
{
3510
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
1,141,310✔
3511
      if (other->args.items[0] == value)
104,910✔
3512
         return other->result;
5,207✔
3513
   }
3514

3515
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
23,555✔
3516
   vcode_add_arg(op, value);
23,555✔
3517

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

3522
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
23,555✔
3523
      vcode_type_t elem = vtype_elem(type);
22,260✔
3524
      op->result = vcode_add_reg(vtype_pointer(elem));
22,260✔
3525

3526
      reg_t *rr = vcode_reg_data(op->result);
22,260✔
3527
      rr->bounds = elem;
22,260✔
3528

3529
      return op->result;
22,260✔
3530
   }
3531
   else
3532
      return (op->result = vcode_add_reg(vtype_pointer(type)));
1,295✔
3533
}
3534

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

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

3549
void emit_jump(vcode_block_t target)
31,276✔
3550
{
3551
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
31,276✔
3552
   vcode_add_target(op, target);
31,276✔
3553
}
31,276✔
3554

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

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

3568
   return var;
37,181✔
3569
}
3570

3571
vcode_reg_t emit_param(vcode_type_t type, vcode_type_t bounds, ident_t name)
26,037✔
3572
{
3573
   assert(active_unit != NULL);
26,037✔
3574

3575
   param_t *p = param_array_alloc(&(active_unit->params));
26,037✔
3576
   memset(p, '\0', sizeof(param_t));
26,037✔
3577
   p->type   = type;
26,037✔
3578
   p->bounds = bounds;
26,037✔
3579
   p->name   = name;
26,037✔
3580
   p->reg    = vcode_add_reg(type);
26,037✔
3581

3582
   reg_t *rr = vcode_reg_data(p->reg);
26,037✔
3583
   rr->bounds = bounds;
26,037✔
3584

3585
   return p->reg;
26,037✔
3586
}
3587

3588
vcode_reg_t emit_load(vcode_var_t var)
45,310✔
3589
{
3590
   // Try scanning backwards through the block for another load or store to
3591
   // this variable
3592
   vcode_reg_t fold = VCODE_INVALID_REG;
45,310✔
3593
   bool aliased = false;
45,310✔
3594
   VCODE_FOR_EACH_OP(other) {
507,530✔
3595
      if (fold == VCODE_INVALID_REG) {
470,817✔
3596
         if (other->kind == VCODE_OP_LOAD && other->address == var)
261,247✔
3597
            fold = other->result;
2,848✔
3598
         else if (other->kind == VCODE_OP_STORE && other->address == var)
258,399✔
3599
            fold = other->args.items[0];
10,212✔
3600
      }
3601

3602
      if (other->kind == VCODE_OP_INDEX && other->address == var)
470,817✔
3603
         aliased = true;
3604
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
470,748✔
3605
         break;   // Nested call captures variables
3606
      else if (other->kind == VCODE_OP_FILE_READ)
462,208✔
3607
         break;   // May write to variable
3608
   }
3609

3610
   var_t *v = vcode_var_data(var);
45,310✔
3611

3612
   if (fold != VCODE_INVALID_REG && !aliased)
45,310✔
3613
      return fold;
3614

3615
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
32,283✔
3616
   op->address = var;
32,283✔
3617
   op->result  = vcode_add_reg(v->type);
32,283✔
3618

3619
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
32,283✔
3620

3621
   reg_t *r = vcode_reg_data(op->result);
32,283✔
3622
   r->bounds = v->bounds;
32,283✔
3623

3624
   return op->result;
32,283✔
3625
}
3626

3627
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
66,859✔
3628
{
3629
   VCODE_FOR_EACH_OP(other) {
711,866✔
3630
      if (other->kind == VCODE_OP_LOAD_INDIRECT
667,298✔
3631
          && other->args.items[0] == reg) {
92,807✔
3632
         return other->result;
5,002✔
3633
      }
3634
      else if (other->kind == VCODE_OP_FCALL
662,296✔
3635
               || other->kind == VCODE_OP_PCALL
662,296✔
3636
               || other->kind == VCODE_OP_STORE
658,118✔
3637
               || other->kind == VCODE_OP_STORE_INDIRECT
650,224✔
3638
               || other->kind == VCODE_OP_MEMSET
647,678✔
3639
               || other->kind == VCODE_OP_COPY
647,446✔
3640
               || other->kind == VCODE_OP_FILE_READ)
645,019✔
3641
         break;   // May write to this pointer
3642
   }
3643

3644
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
61,857✔
3645
   vcode_add_arg(op, reg);
61,857✔
3646

3647
   vcode_type_t rtype = vcode_reg_type(reg);
61,857✔
3648

3649
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
61,857✔
3650
                "load indirect with non-pointer argument");
3651

3652
   vcode_type_t deref = vtype_pointed(rtype);
61,857✔
3653
   op->result = vcode_add_reg(deref);
61,857✔
3654

3655
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
61,857✔
3656

3657
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
61,857✔
3658

3659
   return op->result;
61,857✔
3660
}
3661

3662
void emit_store(vcode_reg_t reg, vcode_var_t var)
46,957✔
3663
{
3664
   // Any previous store to this variable in this block is dead
3665
   VCODE_FOR_EACH_OP(other) {
809,586✔
3666
      if (other->kind == VCODE_OP_STORE && other->address == var) {
773,364✔
3667
         other->kind = VCODE_OP_COMMENT;
245✔
3668
         other->comment =
490✔
3669
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
245✔
3670
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
245✔
3671
      }
3672
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
773,119✔
3673
         break;   // Needs to get variable for display
3674
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
767,173✔
3675
               && other->address == var)
16,169✔
3676
         break;   // Previous value may be used
3677
   }
3678

3679
   var_t *v = vcode_var_data(var);
46,957✔
3680
   reg_t *r = vcode_reg_data(reg);
46,957✔
3681

3682
   op_t *op = vcode_add_op(VCODE_OP_STORE);
46,957✔
3683
   vcode_add_arg(op, reg);
46,957✔
3684
   op->address = var;
46,957✔
3685

3686
   VCODE_ASSERT(vtype_eq(v->type, r->type),
46,957✔
3687
                "variable and stored value do not have same type");
3688
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
46,957✔
3689
}
46,957✔
3690

3691
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
9,676✔
3692
{
3693
   reg_t *p = vcode_reg_data(ptr);
9,676✔
3694
   reg_t *r = vcode_reg_data(reg);
9,676✔
3695

3696
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
9,676✔
3697
   vcode_add_arg(op, reg);
9,676✔
3698
   vcode_add_arg(op, ptr);
9,676✔
3699

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

3707
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
41,082✔
3708
                              vcode_reg_t locus)
3709
{
3710
   // Reuse any previous operation in this block with the same arguments
3711
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,000,040✔
3712
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
57,549✔
3713
         return other->result;
2,320✔
3714
   }
3715

3716
   op_t *op = vcode_add_op(kind);
38,762✔
3717
   vcode_add_arg(op, lhs);
38,762✔
3718
   vcode_add_arg(op, rhs);
38,762✔
3719
   if (locus != VCODE_INVALID_REG)
38,762✔
3720
      vcode_add_arg(op, locus);
4,722✔
3721

3722
   op->result = vcode_add_reg(vcode_reg_type(lhs));
38,762✔
3723

3724
   vcode_type_t lhs_type = vcode_reg_type(lhs);
38,762✔
3725
   vcode_type_t rhs_type = vcode_reg_type(rhs);
38,762✔
3726

3727
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
38,762✔
3728
                "arguments to %s are not the same type", vcode_op_string(kind));
3729

3730
   return op->result;
3731
}
3732

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

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

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

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

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

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

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

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

3781
      vbounds = vtype_int(min, max);
1,892✔
3782
   }
3783

3784
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
2,603✔
3785

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

3789
   return reg;
3790
}
3791

3792
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
28,418✔
3793
{
3794
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
28,418✔
3795
}
3796

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

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

3804
   return result;
798✔
3805
}
3806

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

3817
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
557✔
3818

3819
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
557✔
3820

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

3830
   return reg;
3831
}
3832

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

3840
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
78✔
3841
}
3842

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

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

3850
   return result;
538✔
3851
}
3852

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

3860
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
168✔
3861
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
168✔
3862

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

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

3871
      return reg;
27✔
3872
   }
3873
   else
3874
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
141✔
3875
}
3876

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

3884
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
71✔
3885

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

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

3894
   return reg;
3895
}
3896

3897
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
36,830✔
3898
                               vcode_reg_t locus)
3899
{
3900
   int64_t lconst, rconst;
36,830✔
3901
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
36,830✔
3902
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
36,830✔
3903
   if (l_is_const && r_is_const)
36,830✔
3904
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
16,789✔
3905
   else if (r_is_const && rconst == 0)
20,041✔
3906
      return lhs;
3907
   else if (l_is_const && lconst == 0)
20,023✔
3908
      return rhs;
3909

3910
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
12,569✔
3911
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
12,569✔
3912
      reg_t *lhs_r = vcode_reg_data(lhs);
12,321✔
3913
      reg_t *rhs_r = vcode_reg_data(rhs);
12,321✔
3914

3915
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
12,321✔
3916
      vtype_t *br = vcode_type_data(rhs_r->bounds);
12,321✔
3917

3918
      int64_t rbl = sadd64(bl->low, br->low);
12,321✔
3919
      int64_t rbh = sadd64(bl->high, br->high);
12,321✔
3920

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

3927
      vbounds = vtype_int(rbl, rbh);
12,321✔
3928
   }
3929

3930
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
12,569✔
3931

3932
   if (vbounds != VCODE_INVALID_TYPE)
12,569✔
3933
      vcode_reg_data(reg)->bounds = vbounds;
12,321✔
3934

3935
   return reg;
3936
}
3937

3938
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
34,140✔
3939
{
3940
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
34,140✔
3941
}
3942

3943
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
2,690✔
3944
{
3945
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
2,690✔
3946

3947
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
2,690✔
3948
                "trapping add may only be used with integer types");
3949

3950
   return result;
2,690✔
3951
}
3952

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

3966
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
18,055✔
3967
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
18,055✔
3968
      reg_t *lhs_r = vcode_reg_data(lhs);
17,766✔
3969
      reg_t *rhs_r = vcode_reg_data(rhs);
17,766✔
3970

3971
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
17,766✔
3972
      vtype_t *br = vcode_type_data(rhs_r->bounds);
17,766✔
3973

3974
      int64_t rbl = ssub64(bl->low, br->high);
17,766✔
3975
      int64_t rbh = ssub64(bl->high, br->low);
17,766✔
3976

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

3983
      vbounds = vtype_int(rbl, rbh);
17,766✔
3984
   }
3985

3986
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
18,055✔
3987

3988
   if (vbounds != VCODE_INVALID_TYPE)
18,055✔
3989
      vcode_reg_data(reg)->bounds = vbounds;
17,766✔
3990

3991
   return reg;
3992
}
3993

3994
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
27,268✔
3995
{
3996
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
27,268✔
3997
}
3998

3999
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
4,545✔
4000
{
4001
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
4,545✔
4002

4003
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
4,545✔
4004
                "trapping sub may only be used with integer types");
4005

4006
   return result;
4,545✔
4007
}
4008

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

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

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

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

4044
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
18,933✔
4045
{
4046
   // Try to find a previous index of this var by this offset
4047
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
621,324✔
4048
      if (other->address == var
37,213✔
4049
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
5,359✔
4050
              || (offset != VCODE_INVALID_REG
×
4051
                  && other->args.items[0] == offset)))
×
4052
         return other->result;
5,359✔
4053
   }
4054

4055
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
13,574✔
4056
   op->address = var;
13,574✔
4057

4058
   if (offset != VCODE_INVALID_REG)
13,574✔
4059
      vcode_add_arg(op, offset);
×
4060

4061
   vcode_calculate_var_index_type(op, vcode_var_data(var));
13,574✔
4062

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

4067
   return op->result;
13,574✔
4068
}
4069

4070
vcode_reg_t emit_cast(vcode_type_t type, vcode_type_t bounds, vcode_reg_t reg)
78,710✔
4071
{
4072
   if (vtype_eq(vcode_reg_type(reg), type))
78,710✔
4073
      return reg;
78,710✔
4074

4075
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
61,481✔
4076
   vtype_kind_t to   = vtype_kind(type);
61,481✔
4077

4078
   const bool integral =
122,962✔
4079
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
61,481✔
4080
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
61,481✔
4081

4082
   int64_t value;
61,481✔
4083
   if (integral && vcode_reg_const(reg, &value))
61,481✔
4084
      return emit_const(type, value);
12,289✔
4085

4086
   // Try to find a previous cast of this register to this type
4087
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
894,414✔
4088
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
107,018✔
4089
         return other->result;
10,540✔
4090
   }
4091

4092
   op_t *op = vcode_add_op(VCODE_OP_CAST);
38,652✔
4093
   vcode_add_arg(op, reg);
38,652✔
4094
   op->type   = type;
38,652✔
4095
   op->result = vcode_add_reg(type);
38,652✔
4096

4097
   static const vcode_type_t allowed[][2] = {
38,652✔
4098
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4099
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4100
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4101
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4102
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4103
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4104
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4105
   };
4106

4107
   if (from == VCODE_TYPE_INT && bounds == VCODE_INVALID_TYPE) {
38,652✔
4108
      reg_t *rr = vcode_reg_data(op->result);
7,619✔
4109
      rr->bounds = vcode_reg_bounds(reg);
7,619✔
4110
   }
4111
   else if (to == VCODE_TYPE_INT && bounds != VCODE_INVALID_TYPE) {
31,033✔
4112
      reg_t *rr = vcode_reg_data(op->result);
25,210✔
4113
      rr->bounds = bounds;
25,210✔
4114
   }
4115

4116
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
70,691✔
4117
      if (from == allowed[i][0] && to == allowed[i][1])
70,691✔
4118
         return op->result;
4119
   }
4120

4121
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4122
}
4123

4124
void emit_return(vcode_reg_t reg)
42,870✔
4125
{
4126
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
42,870✔
4127
   if (reg != VCODE_INVALID_REG) {
42,870✔
4128
      vcode_add_arg(op, reg);
24,073✔
4129

4130
      const vtype_kind_t rkind = vcode_reg_kind(reg);
24,073✔
4131
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
24,073✔
4132
         vcode_heap_allocate(reg);
7,414✔
4133
         active_unit->flags |= UNIT_ESCAPING_TLAB;
7,414✔
4134
      }
4135

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

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

4159
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
8,371✔
4160
   vcode_add_arg(op, nets);
8,371✔
4161
   vcode_add_arg(op, nnets);
8,371✔
4162
   vcode_add_arg(op, values);
8,371✔
4163
   vcode_add_arg(op, reject);
8,371✔
4164
   vcode_add_arg(op, after);
8,371✔
4165

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

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

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

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

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

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

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

4214
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
30,759✔
4215
{
4216
   int64_t tconst;
30,759✔
4217
   if (vcode_reg_const(test, &tconst)) {
30,759✔
4218
      emit_jump(!!tconst ? btrue : bfalse);
5,518✔
4219
      return;
3,366✔
4220
   }
4221

4222
   op_t *op = vcode_add_op(VCODE_OP_COND);
27,393✔
4223
   vcode_add_arg(op, test);
27,393✔
4224
   vcode_add_target(op, btrue);
27,393✔
4225
   vcode_add_target(op, bfalse);
27,393✔
4226

4227
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
27,393✔
4228
                "cond test is not a bool");
4229
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
27,393✔
4230
                "invalid cond targets");
4231
}
4232

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

4239
   op_t *op = vcode_add_op(VCODE_OP_NEG);
6,614✔
4240
   vcode_add_arg(op, lhs);
6,614✔
4241
   op->result = vcode_add_reg(vcode_reg_type(lhs));
6,614✔
4242

4243
   return op->result;
6,614✔
4244
}
4245

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

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

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

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

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

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

4276
   return op->result;
230✔
4277
}
4278

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

4289
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
14,870✔
4290
                        vcode_reg_t rfalse)
4291
{
4292
   int64_t tconst;
14,870✔
4293
   if (vcode_reg_const(test, &tconst))
14,870✔
4294
      return !!tconst ? rtrue : rfalse;
3,656✔
4295
   else if (rtrue == rfalse)
11,214✔
4296
      return rtrue;
4297

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

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

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

4316
   return op->result;
10,545✔
4317
}
4318

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

4333
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
6,555✔
4334
{
4335
   vcode_type_t vtbool = vtype_bool();
6,555✔
4336

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

4373
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
6,443✔
4374

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

4379
   return result;
4380
}
4381

4382
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
1,402✔
4383
{
4384
   return emit_logical(VCODE_OP_OR, lhs, rhs);
1,402✔
4385
}
4386

4387
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
4,852✔
4388
{
4389
   return emit_logical(VCODE_OP_AND, lhs, rhs);
4,852✔
4390
}
4391

4392
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
66✔
4393
{
4394
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
66✔
4395
}
4396

4397
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
67✔
4398
{
4399
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
67✔
4400
}
4401

4402
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
97✔
4403
{
4404
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
97✔
4405
}
4406

4407
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
71✔
4408
{
4409
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
71✔
4410
}
4411

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

4418
   op_t *op = vcode_add_op(VCODE_OP_NOT);
1,780✔
4419
   vcode_add_arg(op, arg);
1,780✔
4420

4421
   vcode_type_t vtbool = vtype_bool();
1,780✔
4422
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
1,780✔
4423
                "argument to not is not boolean");
4424

4425
   return (op->result = vcode_add_reg(vtbool));
1,780✔
4426
}
4427

4428
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
40,682✔
4429
{
4430
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,428,800✔
4431
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
160,311✔
4432
         bool match = true;
4433
         for (int i = 0; match && i < ndims; i++) {
12,864✔
4434
            match = other->args.items[i*3 + 1] == dims[i].left
6,452✔
4435
               && other->args.items[i*3 + 2] == dims[i].right
5,366✔
4436
               && other->args.items[i*3 + 3] == dims[i].dir;
11,794✔
4437
         }
4438
         if (match)
6,412✔
4439
            return other->result;
5,302✔
4440
      }
4441
   }
4442

4443
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
35,380✔
4444
   vcode_add_arg(op, data);
35,380✔
4445
   for (int i = 0; i < ndims; i++) {
71,157✔
4446
      vcode_add_arg(op, dims[i].left);
35,777✔
4447
      vcode_add_arg(op, dims[i].right);
35,777✔
4448
      vcode_add_arg(op, dims[i].dir);
35,777✔
4449
   }
4450

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

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

4467
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
70,760✔
4468
      ? vtype_pointed(ptr_type) : ptr_type;
35,380✔
4469

4470
   op->result = vcode_add_reg(
35,380✔
4471
      vtype_uarray(ndims, elem, vcode_reg_bounds(data)));
4472

4473
   return op->result;
35,380✔
4474
}
4475

4476
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
86,837✔
4477
                                  vcode_reg_t array, unsigned dim,
4478
                                  unsigned arg_index)
4479
{
4480
   // Reuse any previous operation in this block with the same arguments
4481
   VCODE_FOR_EACH_OP(other) {
967,898✔
4482
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
929,038✔
4483
          && (rtype == VCODE_INVALID_TYPE
16,258✔
4484
              || vtype_eq(rtype, vcode_reg_type(other->result))))
6,837✔
4485
         return other->result;
16,258✔
4486
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
912,780✔
4487
         return other->args.items[1 + (dim * 3) + arg_index];
31,719✔
4488
   }
4489

4490
   op_t *op = vcode_add_op(o);
38,860✔
4491
   vcode_add_arg(op, array);
38,860✔
4492
   op->dim = dim;
38,860✔
4493

4494
   vcode_type_t atype = vcode_reg_type(array);
38,860✔
4495
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
38,860✔
4496
                "cannot use %s with non-uarray type", vcode_op_string(o));
4497

4498
   vtype_t *vt = vcode_type_data(atype);
38,860✔
4499
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
38,860✔
4500

4501
   if (rtype == VCODE_INVALID_TYPE)
38,860✔
4502
      rtype = vtype_offset();
25,355✔
4503

4504
   return (op->result = vcode_add_reg(rtype));
38,860✔
4505
}
4506

4507
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
31,251✔
4508
{
4509
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
31,251✔
4510
                         array, dim, 0);
4511
}
4512

4513
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
24,612✔
4514
{
4515
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
24,612✔
4516
                         array, dim, 1);
4517
}
4518

4519
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
30,974✔
4520
{
4521
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
30,974✔
4522
                         array, dim, 2);
4523
}
4524

4525
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
39,814✔
4526
{
4527
   VCODE_FOR_EACH_OP(other) {
350,897✔
4528
      if (other->kind == VCODE_OP_UARRAY_LEN) {
331,153✔
4529
         if (other->args.items[0] == array && other->dim == dim)
27,746✔
4530
            return other->result;
9,576✔
4531
      }
4532
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
303,407✔
4533
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
10,494✔
4534
                      "array dimension %d out of bounds", dim);
4535

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

4543
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
19,744✔
4544
   vcode_add_arg(op, array);
19,744✔
4545
   op->dim = dim;
19,744✔
4546

4547
   vcode_type_t atype = vcode_reg_type(array);
19,744✔
4548
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
19,744✔
4549
                "cannot use uarray len with non-uarray type");
4550

4551
   vtype_t *vt = vcode_type_data(atype);
19,744✔
4552
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
19,744✔
4553

4554
   return (op->result = vcode_add_reg(vtype_offset()));
19,744✔
4555
}
4556

4557
vcode_reg_t emit_unwrap(vcode_reg_t array)
29,786✔
4558
{
4559
   VCODE_FOR_EACH_OP(other) {
557,171✔
4560
      if (other->kind == VCODE_OP_WRAP && other->result == array)
536,246✔
4561
         return other->args.items[0];
8,173✔
4562
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
528,073✔
4563
         return other->result;
688✔
4564
   }
4565

4566
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
20,925✔
4567
   vcode_add_arg(op, array);
20,925✔
4568

4569
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
20,925✔
4570
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
20,925✔
4571
                "unwrap can only only be used with uarray types");
4572

4573
   vcode_type_t elem = vt->elem;
20,925✔
4574

4575
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
20,925✔
4576
      ? elem : vtype_pointer(elem);
20,925✔
4577

4578
   op->result = vcode_add_reg(rtype);
20,925✔
4579

4580
   reg_t *rr = vcode_reg_data(op->result);
20,925✔
4581
   rr->bounds = elem;
20,925✔
4582

4583
   return op->result;
20,925✔
4584
}
4585

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

4596
   int64_t dir_const;
15,180✔
4597
   if (vcode_reg_const(dir, &dir_const)) {
15,180✔
4598
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
11,278✔
4599
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
11,278✔
4600

4601
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
11,278✔
4602
         return emit_const(vtype_bool(), 1);
41✔
4603
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
11,237✔
4604
         return emit_const(vtype_bool(), 0);
5,169✔
4605
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
6,068✔
4606
         return emit_const(vtype_bool(), 1);
71✔
4607
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
5,997✔
4608
         return emit_const(vtype_bool(), 0);
1,456✔
4609
      else if (dir_const == RANGE_TO)
4,541✔
4610
         return emit_cmp(VCODE_CMP_GT, left, right);
1,230✔
4611
      else
4612
         return emit_cmp(VCODE_CMP_GT, right, left);
3,311✔
4613
   }
4614

4615
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
3,902✔
4616
   vcode_add_arg(op, left);
3,902✔
4617
   vcode_add_arg(op, right);
3,902✔
4618
   vcode_add_arg(op, dir);
3,902✔
4619

4620
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
3,902✔
4621
                "range left and right have different types");
4622
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
3,902✔
4623
                "dir argument to range length is not int");
4624

4625
   return (op->result = vcode_add_reg(vtype_bool()));
3,902✔
4626
}
4627

4628
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
14,612✔
4629
                              vcode_reg_t dir)
4630
{
4631
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_LENGTH) {
403,576✔
4632
      if (other->args.items[0] == left
5,203✔
4633
          && other->args.items[1] == right
4,170✔
4634
          && other->args.items[2] == dir)
3,917✔
4635
         return other->result;
3,917✔
4636
   }
4637

4638
   int64_t lconst, rconst, dconst;
10,695✔
4639
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
10,695✔
4640
       && vcode_reg_const(right, &rconst)) {
6,787✔
4641

4642
      int64_t diff;
5,365✔
4643
      if (dconst == RANGE_TO)
5,365✔
4644
         diff = rconst - lconst;
3,768✔
4645
      else
4646
         diff = lconst - rconst;
1,597✔
4647

4648
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
5,365✔
4649
   }
4650

4651
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
5,330✔
4652
   vcode_add_arg(op, left);
5,330✔
4653
   vcode_add_arg(op, right);
5,330✔
4654
   vcode_add_arg(op, dir);
5,330✔
4655

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

4661
   return (op->result = vcode_add_reg(vtype_offset()));
5,330✔
4662
}
4663

4664
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
37,405✔
4665
{
4666
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
568,769✔
4667
      if (other->hops == hops && other->address == var)
66,943✔
4668
         return other->result;
6,040✔
4669
   }
4670

4671
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
31,365✔
4672
   op->hops    = hops;
31,365✔
4673
   op->address = var;
31,365✔
4674

4675
   VCODE_ASSERT(hops > 0, "invalid hop count");
31,365✔
4676

4677
   vcode_unit_t vu = active_unit;
31,365✔
4678
   for (int i = 0; i < hops; i++) {
69,677✔
4679
      vu = vu->context;
38,312✔
4680
      VCODE_ASSERT(vu, "hop count is greater than depth");
38,312✔
4681
   }
4682

4683
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
31,365✔
4684

4685
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
31,365✔
4686

4687
   return op->result;
31,365✔
4688
}
4689

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

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

4715
   return (op->result = vcode_add_reg(vtype_signal(type)));
8,684✔
4716
}
4717

4718
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
2,085✔
4719
{
4720
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
2,085✔
4721
   vcode_add_arg(op, signal);
2,085✔
4722
   vcode_add_arg(op, resolution);
2,085✔
4723

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

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

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

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

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

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

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

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

4790
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
7,255✔
4791
{
4792
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
92,264✔
4793
      if (other->args.items[0] == target && other->args.items[1] == count)
13,082✔
4794
         return;
4795
   }
4796

4797
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
7,243✔
4798
   vcode_add_arg(op, target);
7,243✔
4799
   vcode_add_arg(op, count);
7,243✔
4800

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

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

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

4826
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
1,974✔
4827
                                    vcode_reg_t ileft, vcode_reg_t nlits)
4828
{
4829
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
99,985✔
4830
      if (other->args.items[0] == closure
1,414✔
4831
          && other->args.items[1] == ileft
1,411✔
4832
          && other->args.items[2] == nlits)
1,411✔
4833
         return other->result;
1,411✔
4834
   }
4835

4836
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
563✔
4837
                "first argument to resolution wrapper must be closure");
4838

4839
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
563✔
4840
   vcode_add_arg(op, closure);
563✔
4841
   vcode_add_arg(op, ileft);
563✔
4842
   vcode_add_arg(op, nlits);
563✔
4843
   op->subkind = VCODE_CC_VHDL;
563✔
4844

4845
   return (op->result = vcode_add_reg(vtype_resolution(type)));
563✔
4846
}
4847

4848
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t atype,
2,127✔
4849
                         vcode_type_t rtype)
4850
{
4851
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
104,160✔
4852
      if (other->func == func && other->subkind == VCODE_CC_VHDL
1,507✔
4853
          && other->args.items[0] == context)
1,432✔
4854
         return other->result;
1,432✔
4855
   }
4856

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

4863
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
695✔
4864
                "invalid closure context argument");
4865

4866
   return (op->result = vcode_add_reg(vtype_closure(rtype)));
695✔
4867
}
4868

4869
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
24,252✔
4870
{
4871
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
33,690✔
4872
      if (other->func == name && other->subkind == VCODE_CC_VHDL)
18,790✔
4873
         return other->result;
10,577✔
4874
   }
4875

4876
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
13,675✔
4877
   op->func    = name;
13,675✔
4878
   op->subkind = VCODE_CC_VHDL;
13,675✔
4879
   if (context != VCODE_INVALID_REG)
13,675✔
4880
      vcode_add_arg(op, context);
127✔
4881

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

4891
   return (op->result = vcode_add_reg(vtype_context(name)));
13,675✔
4892
}
4893

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

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

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

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

4917
   return (op->result = vcode_add_reg(type));
145✔
4918
}
4919

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

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

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

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

4940
vcode_reg_t emit_context_upref(int hops)
14,216✔
4941
{
4942
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
428,930✔
4943
      if (other->hops == hops)
6,428✔
4944
         return other->result;
6,387✔
4945
   }
4946

4947
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
7,829✔
4948
   op->hops = hops;
7,829✔
4949

4950
   VCODE_ASSERT(hops >= 0, "invalid hop count");
7,829✔
4951

4952
   vcode_unit_t vu = active_unit;
7,829✔
4953
   for (int i = 0; i < hops; i++) {
14,818✔
4954
      vu = vu->context;
6,989✔
4955
      VCODE_ASSERT(vu, "hop count is greater than depth");
6,989✔
4956
   }
4957

4958
   return (op->result = vcode_add_reg(vtype_context(vu->name)));
7,829✔
4959
}
4960

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

4968
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
445✔
4969
                "argument to %s is not a signal", vcode_op_string(opkind));
4970

4971
   return (op->result = vcode_add_reg(vtype_bool()));
445✔
4972
}
4973

4974
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
255✔
4975
{
4976
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
255✔
4977
}
4978

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

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

4992
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
26,050✔
4993
   op->field = field;
26,050✔
4994
   vcode_add_arg(op, record);
26,050✔
4995

4996
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
26,050✔
4997

4998
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
26,050✔
4999
                "argument to record ref must be a pointer");
5000

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

5005
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
26,050✔
5006

5007
   vcode_type_t field_type  = rtype->fields.items[field];
26,050✔
5008
   vcode_type_t bounds_type = field_type;
26,050✔
5009
   vcode_type_t result_type = field_type;
26,050✔
5010

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

5019
   op->result = vcode_add_reg(vtype_pointer(result_type));
26,050✔
5020

5021
   reg_t *rr = vcode_reg_data(op->result);
26,050✔
5022
   rr->bounds = bounds_type;
26,050✔
5023

5024
   return op->result;
26,050✔
5025
}
5026

5027
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
27,534✔
5028
{
5029
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
763,348✔
5030
      if (other->args.items[0] == array && other->args.items[1] == offset)
37,513✔
5031
         return other->result;
897✔
5032
   }
5033

5034
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
26,637✔
5035
   vcode_add_arg(op, array);
26,637✔
5036
   vcode_add_arg(op, offset);
26,637✔
5037

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

5046
   op->result = vcode_add_reg(rtype);
26,637✔
5047

5048
   reg_t *rr = vcode_reg_data(op->result);
26,637✔
5049
   rr->bounds = vcode_reg_bounds(array);
26,637✔
5050

5051
   return op->result;
26,637✔
5052
}
5053

5054
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
17,323✔
5055
{
5056
   int64_t cconst;
17,323✔
5057
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
17,323✔
5058
       && cconst == 0)
8,252✔
5059
      return;
4,570✔
5060
   else if (dest == src)
17,203✔
5061
      return;
5062

5063
   op_t *op = vcode_add_op(VCODE_OP_COPY);
12,753✔
5064
   vcode_add_arg(op, dest);
12,753✔
5065
   vcode_add_arg(op, src);
12,753✔
5066
   if (count != VCODE_INVALID_REG)
12,753✔
5067
      vcode_add_arg(op, count);
11,300✔
5068

5069
   vcode_type_t dtype = vcode_reg_type(dest);
12,753✔
5070
   vcode_type_t stype = vcode_reg_type(src);
12,753✔
5071

5072
   vtype_kind_t dkind = vtype_kind(dtype);
12,753✔
5073
   vtype_kind_t skind = vtype_kind(stype);
12,753✔
5074

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

5085
   op->type = vtype_pointed(dtype);
12,753✔
5086
}
5087

5088
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
3,963✔
5089
{
5090
   VCODE_FOR_EACH_OP(other) {
59,501✔
5091
      if (other->kind == VCODE_OP_CLEAR_EVENT)
55,570✔
5092
         break;
5093
      else if (other->kind == VCODE_OP_SCHED_EVENT
55,540✔
5094
               && other->args.items[0] == nets
3,925✔
5095
               && other->args.items[1] == n_elems)
5✔
5096
         return;
5097
   }
5098

5099
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
3,961✔
5100
   vcode_add_arg(op, nets);
3,961✔
5101
   vcode_add_arg(op, n_elems);
3,961✔
5102

5103
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
3,961✔
5104
                "nets argument to sched event must be signal");
5105
}
5106

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

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

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

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

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

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

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

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

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

5160
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
5,156✔
5161
   vcode_add_arg(op, ptr);
5,156✔
5162
   vcode_add_arg(op, value);
5,156✔
5163
   vcode_add_arg(op, len);
5,156✔
5164

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

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

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

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

5192
   if (is_const) {
429✔
5193
      emit_jump(def);
×
5194
      return;
×
5195
   }
5196

5197
   op_t *op = vcode_add_op(VCODE_OP_CASE);
429✔
5198
   vcode_add_arg(op, value);
429✔
5199
   vcode_add_target(op, def);
429✔
5200

5201
   for (int i = 0; i < ncases; i++) {
4,241✔
5202
      vcode_add_arg(op, cases[i]);
3,812✔
5203
      vcode_add_target(op, blocks[i]);
3,812✔
5204

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

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

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

5220
   return (op->result = vcode_add_reg(vtype_bool()));
27✔
5221
}
5222

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

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

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

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

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

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

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

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

5280
vcode_reg_t emit_null(vcode_type_t type)
5,809✔
5281
{
5282
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
97,627✔
5283
      if (vtype_eq(vcode_reg_type(other->result), type))
1,810✔
5284
         return other->result;
752✔
5285
   }
5286

5287
   op_t *op = vcode_add_op(VCODE_OP_NULL);
5,057✔
5288
   op->result = vcode_add_reg(type);
5,057✔
5289

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

5295
   return op->result;
5296
}
5297

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

5304
   op->result = vcode_add_reg(vtype_access(type));
421✔
5305

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

5315
   return op->result;
421✔
5316
}
5317

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

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

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

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

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

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

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

5358
   vcode_type_t vtype = vcode_reg_type(reg);
1,907✔
5359

5360
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
1,907✔
5361
                "all argument must be an access");
5362

5363
   vcode_type_t pointed = vtype_pointed(vtype);
1,907✔
5364
   op->result = vcode_add_reg(vtype_pointer(pointed));
1,907✔
5365

5366
   reg_t *rr = vcode_reg_data(op->result);
1,907✔
5367
   rr->bounds = pointed;
1,907✔
5368

5369
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
1,907✔
5370
                "cannot dereference opaque type");
5371

5372
   return op->result;
5373
}
5374

5375
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
11,337✔
5376
{
5377
   block_t *b = &(active_unit->blocks.items[active_block]);
11,337✔
5378
   for (int i = b->ops.count - 1; i >= 0; i--) {
362,180✔
5379
      const op_t *other = &(b->ops.items[i]);
351,483✔
5380
      if (other->kind == kind && other->args.items[0] == sig)
351,483✔
5381
         return other->result;
640✔
5382
   }
5383

5384
   op_t *op = vcode_add_op(kind);
10,697✔
5385
   vcode_add_arg(op, sig);
10,697✔
5386

5387
   vcode_type_t stype = vcode_reg_type(sig);
10,697✔
5388
   op->type = stype;
10,697✔
5389

5390
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
10,697✔
5391
                "argument r%d to resolved is not a signal", sig);
5392

5393
   vcode_type_t rtype = vtype_base(stype);
10,697✔
5394

5395
   const vtype_kind_t rkind = vtype_kind(rtype);
10,697✔
5396
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
10,697✔
5397
      rtype = vtype_elem(rtype);
×
5398

5399
   VCODE_ASSERT(vtype_is_scalar(rtype),
10,697✔
5400
                "resolved signal base type must be scalar");
5401

5402
   op->result = vcode_add_reg(vtype_pointer(rtype));
10,697✔
5403

5404
   reg_t *rr = vcode_reg_data(op->result);
10,697✔
5405
   rr->bounds = rtype;
10,697✔
5406

5407
   return op->result;
10,697✔
5408
}
5409

5410
vcode_reg_t emit_resolved(vcode_reg_t sig)
11,296✔
5411
{
5412
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
11,296✔
5413
}
5414

5415
vcode_reg_t emit_last_value(vcode_reg_t sig)
41✔
5416
{
5417
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
41✔
5418
}
5419

5420
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
42✔
5421
{
5422
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
42✔
5423
   vcode_add_arg(op, signal);
42✔
5424
   if (len != VCODE_INVALID_REG)
42✔
5425
      vcode_add_arg(op, len);
30✔
5426

5427
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
42✔
5428
                "signal argument to last event must have signal type");
5429
   VCODE_ASSERT(len == VCODE_INVALID_REG
42✔
5430
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5431
                "length argument to last event must have offset type");
5432

5433
   return (op->result = vcode_add_reg(vtype_time()));
42✔
5434
}
5435

5436
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
36✔
5437
{
5438
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
36✔
5439
   vcode_add_arg(op, signal);
36✔
5440
   if (len != VCODE_INVALID_REG)
36✔
5441
      vcode_add_arg(op, len);
27✔
5442

5443
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5444
                "signal argument to last active must have signal type");
5445
   VCODE_ASSERT(len == VCODE_INVALID_REG
36✔
5446
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5447
                "length argument to last active must have offset type");
5448

5449
   return (op->result = vcode_add_reg(vtype_time()));
36✔
5450
}
5451

5452
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,337✔
5453
{
5454
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,337✔
5455
   vcode_add_arg(op, signal);
4,337✔
5456
   vcode_add_arg(op, locus);
4,337✔
5457

5458
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,337✔
5459
                "signal argument must have signal type");
5460
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
4,337✔
5461
                "locus argument must have debug locus type");
5462
}
4,337✔
5463

5464
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
30✔
5465
{
5466
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
30✔
5467
   vcode_add_arg(op, signal);
30✔
5468
   vcode_add_arg(op, len);
30✔
5469

5470
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
30✔
5471
                "signal argument to last active must have signal type");
5472
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
30✔
5473
                "length argument to last active must have offset type");
5474

5475
   return (op->result = vcode_add_reg(vtype_bool()));
30✔
5476
}
5477

5478
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
24✔
5479
{
5480
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
24✔
5481
   vcode_add_arg(op, signal);
24✔
5482
   if (len != VCODE_INVALID_REG)
24✔
5483
      vcode_add_arg(op, len);
3✔
5484

5485
   vcode_type_t signal_type = vcode_reg_type(signal);
24✔
5486

5487
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
24✔
5488
                "signal argument to last active must have signal type");
5489
   VCODE_ASSERT(len == VCODE_INVALID_REG
24✔
5490
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5491
                "length argument to last active must have offset type");
5492

5493
   vcode_type_t base_type = vtype_base(signal_type);
24✔
5494
   op->result = vcode_add_reg(vtype_pointer(base_type));
24✔
5495

5496
   reg_t *rr = vcode_reg_data(op->result);
24✔
5497
   rr->bounds = base_type;
24✔
5498

5499
   return op->result;
24✔
5500
}
5501

5502
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
17,645✔
5503
                       vcode_reg_t dim)
5504
{
5505
   if (rlen == llen)
17,645✔
5506
      return;
5507

5508
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
111,616✔
5509
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
1,820✔
5510
         return;
5511
   }
5512

5513
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
5,191✔
5514
   vcode_add_arg(op, llen);
5,191✔
5515
   vcode_add_arg(op, rlen);
5,191✔
5516
   vcode_add_arg(op, locus);
5,191✔
5517
   if (dim != VCODE_INVALID_REG)
5,191✔
5518
      vcode_add_arg(op, dim);
24✔
5519

5520
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
5,191✔
5521
                "locus argument to length check must be a debug locus");
5522
}
5523

5524
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
538✔
5525
{
5526
   int64_t cval;
538✔
5527
   if (vcode_reg_const(exp, &cval) && cval >= 0)
538✔
5528
      return;
33✔
5529

5530
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
3,159✔
5531
      if (other->args.items[0] == exp)
6✔
5532
         return;
5533
   }
5534

5535
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
505✔
5536
   vcode_add_arg(op, exp);
505✔
5537
   vcode_add_arg(op, locus);
505✔
5538

5539
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
505✔
5540
                "exp argument to exponent check must be a integer");
5541
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
505✔
5542
                "locus argument to exponent check must be a debug locus");
5543
}
5544

5545
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
561✔
5546
{
5547
   int64_t cval;
561✔
5548
   if (vcode_reg_const(denom, &cval) && cval != 0)
561✔
5549
      return;
466✔
5550

5551
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
3,469✔
5552
      if (other->args.items[0] == denom)
56✔
5553
         return;
5554
   }
5555

5556
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
95✔
5557
   vcode_add_arg(op, denom);
95✔
5558
   vcode_add_arg(op, locus);
95✔
5559

5560
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
95✔
5561
                "denom argument to zero check must be a integer");
5562
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
95✔
5563
                "locus argument to zero check must be a debug locus");
5564
}
5565

5566
bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
85,869✔
5567
                            vcode_reg_t right, vcode_reg_t dir)
5568
{
5569
   int64_t dconst;
85,869✔
5570
   if (vcode_reg_const(dir, &dconst)) {
85,869✔
5571
      int64_t lconst, rconst;
79,243✔
5572
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
79,243✔
5573
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
70,932✔
5574
            || (dconst == RANGE_DOWNTO && rconst > lconst);
145,185✔
5575

5576
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
74,253✔
5577

5578
         const bool ok_static =
148,506✔
5579
            (dconst == RANGE_TO
5580
             && bounds->low >= lconst && bounds->high <= rconst)
70,932✔
5581
            || (dconst == RANGE_DOWNTO
9,591✔
5582
                && bounds->low >= rconst && bounds->high <= lconst)
3,321✔
5583
            || (!is_null && (reg == left || reg == right));
80,634✔
5584

5585
         return ok_static;
78,101✔
5586
      }
5587
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
4,990✔
5588
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
4,607✔
5589
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
4,607✔
5590

5591
         assert(lbounds->kind == VCODE_TYPE_REAL);
4,607✔
5592
         assert(rbounds->kind == VCODE_TYPE_REAL);
4,607✔
5593

5594
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
4,607✔
5595
         assert(bounds->kind == VCODE_TYPE_REAL);
4,607✔
5596

5597
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
4,607✔
5598
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
3,848✔
5599
            // Covers the complete double range so can never overflow
5600
            return true;
5601
         }
5602
      }
5603
   }
5604

5605
   return false;
5606
}
5607

5608
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
37,200✔
5609
                              vcode_reg_t left, vcode_reg_t right,
5610
                              vcode_reg_t dir, vcode_reg_t locus,
5611
                              vcode_reg_t hint)
5612
{
5613
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,033,540✔
5614
      if (other->args.items[0] == reg && other->args.items[1] == left
10,940✔
5615
          && other->args.items[2] == right && other->args.items[3] == dir)
208✔
5616
         return;
5617
   }
5618

5619
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
36,992✔
5620
      emit_comment("Elided bounds check for r%d", reg);
25,506✔
5621
      return;
25,506✔
5622
   }
5623

5624
   op_t *op = vcode_add_op(kind);
11,486✔
5625
   vcode_add_arg(op, reg);
11,486✔
5626
   vcode_add_arg(op, left);
11,486✔
5627
   vcode_add_arg(op, right);
11,486✔
5628
   vcode_add_arg(op, dir);
11,486✔
5629
   vcode_add_arg(op, locus);
11,486✔
5630
   vcode_add_arg(op, hint);
11,486✔
5631

5632
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
11,486✔
5633
                "locus argument to bounds check must be a debug locus");
5634
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
11,486✔
5635
                "hint argument to bounds check must be a debug locus");
5636
}
5637

5638
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
2,663✔
5639
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5640
{
5641
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
2,663✔
5642
}
2,663✔
5643

5644
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
34,537✔
5645
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5646
{
5647
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
34,537✔
5648
}
34,537✔
5649

5650
void emit_push_scope(vcode_reg_t locus, vcode_type_t type)
1,064✔
5651
{
5652
   op_t *op = vcode_add_op(VCODE_OP_PUSH_SCOPE);
1,064✔
5653
   vcode_add_arg(op, locus);
1,064✔
5654
   op->type = type;
1,064✔
5655

5656
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,064✔
5657
                "locus argument to push scope must be a debug locus");
5658
}
1,064✔
5659

5660
void emit_pop_scope(void)
1,064✔
5661
{
5662
   vcode_add_op(VCODE_OP_POP_SCOPE);
1,064✔
5663
}
1,064✔
5664

5665
vcode_reg_t emit_debug_locus(ident_t unit, ptrdiff_t offset)
88,582✔
5666
{
5667
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
3,018,840✔
5668
      if (other->ident == unit && other->tag == offset)
350,991✔
5669
         return other->result;
4,432✔
5670
   }
5671

5672
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
84,150✔
5673
   op->ident = unit;
84,150✔
5674
   op->value = offset;
84,150✔
5675

5676
   return (op->result = vcode_add_reg(vtype_debug_locus()));
84,150✔
5677
}
5678

5679
void emit_debug_out(vcode_reg_t reg)
×
5680
{
5681
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
5682
   vcode_add_arg(op, reg);
×
5683
}
×
5684

5685
void emit_cover_stmt(uint32_t tag)
715✔
5686
{
5687
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
715✔
5688
   op->tag = tag;
715✔
5689
}
715✔
5690

5691
void emit_cover_branch(vcode_reg_t test, uint32_t tag, uint32_t flags)
308✔
5692
{
5693
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
308✔
5694
   vcode_add_arg(op, test);
308✔
5695
   op->tag = tag;
308✔
5696
   op->subkind = flags;
308✔
5697
}
308✔
5698

5699
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
281✔
5700
{
5701
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
281✔
5702
   vcode_add_arg(op, signal);
281✔
5703
   op->tag = tag;
281✔
5704
}
281✔
5705

5706
void emit_cover_expr(vcode_reg_t new_mask, uint32_t tag)
318✔
5707
{
5708
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
318✔
5709
   vcode_add_arg(op, new_mask);
318✔
5710
   op->tag = tag;
318✔
5711
}
318✔
5712

5713
void emit_unreachable(vcode_reg_t locus)
153✔
5714
{
5715
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
153✔
5716
   if (locus != VCODE_INVALID_REG)
153✔
5717
      vcode_add_arg(op, locus);
105✔
5718
}
153✔
5719

5720
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
1,443✔
5721
{
5722
   active_unit->flags |= UNIT_UNDEFINED;
1,443✔
5723

5724
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
1,443✔
5725
   op->result = vcode_add_reg(type);
1,443✔
5726
   vcode_reg_data(op->result)->bounds = bounds;
1,443✔
5727

5728
   return op->result;
1,443✔
5729
}
5730

5731
void emit_debug_info(const loc_t *loc)
1,538,570✔
5732
{
5733
   if (!loc_invalid_p(loc))
1,538,570✔
5734
      vcode_block_data()->last_loc = *loc;
1,462,840✔
5735
}
1,538,570✔
5736

5737
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
3,765✔
5738
{
5739
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
136,081✔
5740
      if (other->args.items[0] == context && other->ident == name)
5,785✔
5741
         return other->result;
1,262✔
5742
   }
5743

5744
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
2,503✔
5745
   vcode_add_arg(op, context);
2,503✔
5746
   op->ident = name;
2,503✔
5747

5748
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
2,503✔
5749
                "first argument to link var must be context");
5750

5751
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
2,503✔
5752
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
79✔
5753
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
79✔
5754
   }
5755
   else {
5756
      op->result = vcode_add_reg(vtype_pointer(type));
2,424✔
5757
      vcode_reg_data(op->result)->bounds = type;
2,424✔
5758
   }
5759

5760
   return op->result;
2,503✔
5761
}
5762

5763
vcode_reg_t emit_link_package(ident_t name)
19,545✔
5764
{
5765
   VCODE_FOR_EACH_OP(other) {
780,398✔
5766
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
769,719✔
5767
         return other->result;
5,497✔
5768
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
764,222✔
5769
         return other->result;
3,369✔
5770
   }
5771

5772
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
10,679✔
5773
   op->ident = name;
10,679✔
5774

5775
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
10,679✔
5776

5777
   return (op->result = vcode_add_reg(vtype_context(name)));
10,679✔
5778
}
5779

5780
vcode_reg_t emit_link_instance(ident_t name, vcode_reg_t locus)
108✔
5781
{
5782
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_INSTANCE) {
510✔
5783
      if (other->ident == name)
39✔
5784
         return other->result;
24✔
5785
   }
5786

5787
   op_t *op = vcode_add_op(VCODE_OP_LINK_INSTANCE);
84✔
5788
   vcode_add_arg(op, locus);
84✔
5789
   op->ident = name;
84✔
5790

5791
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
84✔
5792
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
84✔
5793
                "locus argument to link instance must be a debug locus");
5794

5795
   return (op->result = vcode_add_reg(vtype_context(name)));
84✔
5796
}
5797

5798
void emit_enter_state(vcode_reg_t state)
57✔
5799
{
5800
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
549✔
5801
      if (other->args.items[0] == state)
×
5802
         return;
5803
   }
5804

5805
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
57✔
5806
   vcode_add_arg(op, state);
57✔
5807

5808
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
57✔
5809
                "state must have integer type");
5810
}
5811

5812
vcode_reg_t emit_reflect_value(ident_t ptype, vcode_reg_t value,
45✔
5813
                               vcode_reg_t context, vcode_reg_t locus,
5814
                               vcode_reg_t bounds)
5815
{
5816
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
45✔
5817
   vcode_add_arg(op, value);
45✔
5818
   vcode_add_arg(op, context);
45✔
5819
   vcode_add_arg(op, locus);
45✔
5820
   if (bounds != VCODE_INVALID_REG)
45✔
5821
      vcode_add_arg(op, bounds);
6✔
5822

5823
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
45✔
5824
                "invalid reflect value context argument");
5825
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5826
                "locus argument to reflect value must be a debug locus");
5827

5828
   return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype))));
45✔
5829
}
5830

5831
vcode_reg_t emit_reflect_subtype(ident_t ptype, vcode_reg_t context,
42✔
5832
                                 vcode_reg_t locus, vcode_reg_t bounds)
5833
{
5834
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
5835
   vcode_add_arg(op, context);
42✔
5836
   vcode_add_arg(op, locus);
42✔
5837
   if (bounds != VCODE_INVALID_REG)
42✔
5838
      vcode_add_arg(op, bounds);
×
5839

5840
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
5841
                "invalid reflect value context argument");
5842
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
5843
                "locus argument to reflect value must be a debug locus");
5844

5845
   return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype))));
42✔
5846
}
5847

5848
vcode_reg_t emit_function_trigger(vcode_reg_t closure)
12✔
5849
{
5850
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
12✔
5851
   vcode_add_arg(op, closure);
12✔
5852

5853
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
12✔
5854
                "argument to function trigger must be a closure");
5855

5856
   return (op->result = vcode_add_reg(vtype_trigger()));
12✔
5857
}
5858

5859
void emit_add_trigger(vcode_reg_t trigger)
48✔
5860
{
5861
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
48✔
5862
   vcode_add_arg(op, trigger);
48✔
5863

5864
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
48✔
5865
                "add trigger argument must be trigger");
5866
}
48✔
5867

5868
static void vcode_write_unit(vcode_unit_t unit, fbuf_t *f,
×
5869
                             ident_wr_ctx_t ident_wr_ctx,
5870
                             loc_wr_ctx_t *loc_wr_ctx)
5871
{
5872
   write_u8(unit->kind, f);
×
5873
   ident_write(unit->name, ident_wr_ctx);
×
5874
   fbuf_put_int(f, unit->result);
×
5875
   fbuf_put_int(f, unit->flags);
×
5876
   fbuf_put_int(f, unit->depth);
×
5877

5878
   if (unit->offset < 0) {
×
5879
      object_t *obj = object_from_locus(unit->module, unit->offset, NULL);
×
5880
      object_locus(obj, &unit->module, &unit->offset);
×
5881
   }
5882

5883
   ident_write(unit->module, ident_wr_ctx);
×
5884
   fbuf_put_uint(f, unit->offset);
×
5885

5886
   if (unit->context != NULL) {
×
5887
      vcode_select_unit(unit);
×
5888
      vcode_select_unit(vcode_unit_context());
×
5889
      ident_write(vcode_unit_name(), ident_wr_ctx);
×
5890
      vcode_close();
×
5891
   }
5892
   else
5893
      ident_write(NULL, ident_wr_ctx);
×
5894

5895
   fbuf_put_uint(f, unit->blocks.count);
×
5896
   for (unsigned i = 0; i < unit->blocks.count; i++) {
×
5897
      const block_t *b = &(unit->blocks.items[i]);
×
5898
      fbuf_put_uint(f, b->ops.count);
×
5899

5900
      for (unsigned j = 0; j < b->ops.count; j++) {
×
5901
         op_t *op = &(b->ops.items[j]);
×
5902

5903
         if (op->kind == VCODE_OP_DEBUG_LOCUS)
×
5904
            object_fixup_locus(op->ident, &op->value);
×
5905

5906
         fbuf_put_uint(f, op->kind);
×
5907
         fbuf_put_uint(f, op->result);
×
5908
         loc_write(&(op->loc), loc_wr_ctx);
×
5909

5910
         fbuf_put_uint(f, op->args.count);
×
5911
         for (unsigned k = 0; k < op->args.count; k++)
×
5912
            fbuf_put_uint(f, op->args.items[k]);
×
5913

5914
         if (OP_HAS_TARGET(op->kind)) {
×
5915
            fbuf_put_uint(f, op->targets.count);
×
5916
            for (unsigned k = 0; k < op->targets.count; k++)
×
5917
               fbuf_put_uint(f, op->targets.items[k]);
×
5918
         }
5919

5920
         if (OP_HAS_TYPE(op->kind))
×
5921
            fbuf_put_uint(f, op->type);
×
5922
         if (OP_HAS_ADDRESS(op->kind))
×
5923
            fbuf_put_uint(f, op->address);
×
5924
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
×
5925
            ident_write(op->func, ident_wr_ctx);
×
5926
         if (OP_HAS_SUBKIND(op->kind))
×
5927
            fbuf_put_uint(f, op->subkind);
×
5928
         if (OP_HAS_CMP(op->kind))
×
5929
            fbuf_put_uint(f, op->cmp);
×
5930
         if (OP_HAS_VALUE(op->kind))
×
5931
            fbuf_put_int(f, op->value);
×
5932
         if (OP_HAS_REAL(op->kind))
×
5933
            write_double(op->real, f);
×
5934
         if (OP_HAS_COMMENT(op->kind))
×
5935
            ;   // Do not save comments
5936
         if (OP_HAS_DIM(op->kind))
×
5937
            fbuf_put_uint(f, op->dim);
×
5938
         if (OP_HAS_HOPS(op->kind))
×
5939
            fbuf_put_uint(f, op->hops);
×
5940
         if (OP_HAS_FIELD(op->kind))
×
5941
            fbuf_put_uint(f, op->field);
×
5942
         if (OP_HAS_TAG(op->kind))
×
5943
            fbuf_put_uint(f, op->tag);
×
5944
      }
5945
   }
5946

5947
   fbuf_put_uint(f, unit->regs.count);
×
5948
   for (unsigned i = 0; i < unit->regs.count; i++) {
×
5949
      const reg_t *r = &(unit->regs.items[i]);
×
5950
      fbuf_put_uint(f, r->type);
×
5951
      fbuf_put_uint(f, r->bounds);
×
5952
   }
5953

5954
   fbuf_put_uint(f, unit->types.count);
×
5955
   for (unsigned i = 0; i < unit->types.count; i++) {
×
5956
      const vtype_t *t = &(unit->types.items[i]);
×
5957
      fbuf_put_uint(f, t->kind);
×
5958
      switch (t->kind) {
×
5959
      case VCODE_TYPE_INT:
×
5960
      case VCODE_TYPE_OFFSET:
5961
         fbuf_put_int(f, t->repr);
×
5962
         fbuf_put_int(f, t->low);
×
5963
         fbuf_put_int(f, t->high);
×
5964
         break;
×
5965

5966
      case VCODE_TYPE_REAL:
×
5967
         write_double(t->rlow, f);
×
5968
         write_double(t->rhigh, f);
×
5969
         break;
×
5970

5971
      case VCODE_TYPE_CARRAY:
×
5972
      case VCODE_TYPE_UARRAY:
5973
         fbuf_put_uint(f, t->dims);
×
5974
         fbuf_put_uint(f, t->size);
×
5975
         fbuf_put_uint(f, t->elem);
×
5976
         fbuf_put_uint(f, t->bounds);
×
5977
         break;
×
5978

5979
      case VCODE_TYPE_ACCESS:
×
5980
      case VCODE_TYPE_POINTER:
5981
         fbuf_put_uint(f, t->pointed);
×
5982
         break;
×
5983

5984
      case VCODE_TYPE_FILE:
×
5985
      case VCODE_TYPE_SIGNAL:
5986
      case VCODE_TYPE_RESOLUTION:
5987
      case VCODE_TYPE_CLOSURE:
5988
         fbuf_put_uint(f, t->base);
×
5989
         break;
×
5990

5991
      case VCODE_TYPE_OPAQUE:
5992
      case VCODE_TYPE_DEBUG_LOCUS:
5993
      case VCODE_TYPE_TRIGGER:
5994
         break;
5995

5996
      case VCODE_TYPE_CONTEXT:
×
5997
         ident_write(t->name, ident_wr_ctx);
×
5998
         break;
×
5999

6000
      case VCODE_TYPE_RECORD:
×
6001
         ident_write(t->name, ident_wr_ctx);
×
6002
         fbuf_put_uint(f, t->fields.count);
×
6003
         for (unsigned j = 0; j < t->fields.count; j++)
×
6004
            fbuf_put_uint(f, t->fields.items[j]);
×
6005
         break;
6006
      }
6007
   }
×
6008

6009
   fbuf_put_uint(f, unit->vars.count);
×
6010
   for (unsigned i = 0; i < unit->vars.count; i++) {
×
6011
      const var_t *v = &(unit->vars.items[i]);
×
6012
      fbuf_put_uint(f, v->type);
×
6013
      fbuf_put_uint(f, v->bounds);
×
6014
      ident_write(v->name, ident_wr_ctx);
×
6015
      fbuf_put_uint(f, v->flags);
×
6016
   }
6017

6018
   fbuf_put_uint(f, unit->params.count);
×
6019
   for (unsigned i = 0; i < unit->params.count; i++) {
×
6020
      const param_t *p = &(unit->params.items[i]);
×
6021
      fbuf_put_uint(f, p->type);
×
6022
      fbuf_put_uint(f, p->bounds);
×
6023
      ident_write(p->name, ident_wr_ctx);
×
6024
      fbuf_put_uint(f, p->reg);
×
6025
   }
6026

6027
   if (unit->next != NULL)
×
6028
      vcode_write_unit(unit->next, f, ident_wr_ctx, loc_wr_ctx);
×
6029

6030
   if (unit->children != NULL)
×
6031
      vcode_write_unit(unit->children, f, ident_wr_ctx, loc_wr_ctx);
6032
}
×
6033

6034
void vcode_write(vcode_unit_t unit, fbuf_t *f, ident_wr_ctx_t ident_ctx,
×
6035
                 loc_wr_ctx_t *loc_ctx)
6036
{
6037
   assert(unit->context == NULL);
×
6038

6039
   write_u8(VCODE_VERSION, f);
×
6040

6041
   vcode_write_unit(unit, f, ident_ctx, loc_ctx);
×
6042
   write_u8(0xff, f);  // End marker
×
6043
}
×
6044

6045
static vcode_unit_t vcode_read_unit(fbuf_t *f, ident_rd_ctx_t ident_rd_ctx,
×
6046
                                    loc_rd_ctx_t *loc_rd_ctx, hash_t *seen)
6047
{
6048
   const uint8_t marker = read_u8(f);
×
6049
   if (marker == 0xff)
×
6050
      return false;
6051

6052
   vcode_unit_t unit = xcalloc(sizeof(struct _vcode_unit));
×
6053
   unit->kind   = marker;
×
6054
   unit->name   = ident_read(ident_rd_ctx);
×
6055
   unit->result = fbuf_get_int(f);
×
6056
   unit->flags  = fbuf_get_int(f);
×
6057
   unit->depth  = fbuf_get_int(f);
×
6058
   unit->module = ident_read(ident_rd_ctx);
×
6059
   unit->offset = fbuf_get_uint(f);
×
6060

6061
   hash_put(seen, unit->name, unit);
×
6062

6063
   ident_t context_name = ident_read(ident_rd_ctx);
×
6064
   if (context_name != NULL) {
×
6065
      unit->context = hash_get(seen, context_name);
×
6066
      if (unit->context == NULL)
×
6067
         fatal("%s references nonexistent context %s", fbuf_file_name(f),
×
6068
               istr(context_name));
6069

6070
      vcode_add_child(unit->context, unit);
×
6071
   }
6072
   else
6073
      unit->context = NULL;
×
6074

6075
   block_array_resize(&(unit->blocks), fbuf_get_uint(f), 0);
×
6076
   for (unsigned i = 0; i < unit->blocks.count; i++) {
×
6077
      block_t *b = &(unit->blocks.items[i]);
×
6078
      op_array_resize(&(b->ops), fbuf_get_uint(f), 0);
×
6079

6080
      for (unsigned j = 0; j < b->ops.count; j++) {
×
6081
         op_t *op = &(b->ops.items[j]);
×
6082

6083
         op->kind = fbuf_get_uint(f);
×
6084
         op->result = fbuf_get_uint(f);
×
6085
         loc_read(&(op->loc), loc_rd_ctx);
×
6086

6087
         vcode_reg_array_resize(&(op->args), fbuf_get_uint(f), 0);
×
6088
         for (unsigned k = 0; k < op->args.count; k++)
×
6089
            op->args.items[k] = fbuf_get_uint(f);
×
6090

6091
         if (OP_HAS_TARGET(op->kind)) {
×
6092
            vcode_block_array_resize(&(op->targets), fbuf_get_uint(f), 0);
×
6093
            for (unsigned k = 0; k < op->targets.count; k++)
×
6094
               op->targets.items[k] = fbuf_get_uint(f);
×
6095
         }
6096

6097
         if (OP_HAS_TYPE(op->kind))
×
6098
            op->type = fbuf_get_uint(f);
×
6099
         if (OP_HAS_ADDRESS(op->kind))
×
6100
            op->address = fbuf_get_uint(f);
×
6101
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
×
6102
            op->func = ident_read(ident_rd_ctx);
×
6103
         if (OP_HAS_SUBKIND(op->kind))
×
6104
            op->subkind = fbuf_get_uint(f);
×
6105
         if (OP_HAS_CMP(op->kind))
×
6106
            op->cmp = fbuf_get_uint(f);
×
6107
         if (OP_HAS_VALUE(op->kind))
×
6108
            op->value = fbuf_get_int(f);
×
6109
         if (OP_HAS_REAL(op->kind))
×
6110
            op->real = read_double(f);
×
6111
         if (OP_HAS_COMMENT(op->kind))
×
6112
            op->comment = NULL;
×
6113
         if (OP_HAS_DIM(op->kind))
×
6114
            op->dim = fbuf_get_uint(f);
×
6115
         if (OP_HAS_HOPS(op->kind))
×
6116
            op->hops = fbuf_get_uint(f);
×
6117
         if (OP_HAS_FIELD(op->kind))
×
6118
            op->field = fbuf_get_uint(f);
×
6119
         if (OP_HAS_TAG(op->kind))
×
6120
            op->tag = fbuf_get_uint(f);
×
6121
      }
6122
   }
6123

6124
   reg_array_resize(&(unit->regs), fbuf_get_uint(f), 0);
×
6125
   for (unsigned i = 0; i < unit->regs.count; i++) {
×
6126
      reg_t *r = &(unit->regs.items[i]);
×
6127
      r->type = fbuf_get_uint(f);
×
6128
      r->bounds = fbuf_get_uint(f);
×
6129
   }
6130

6131
   vtype_array_resize(&(unit->types), fbuf_get_uint(f), 0);
×
6132
   for (unsigned i = 0; i < unit->types.count; i++) {
×
6133
      vtype_t *t = &(unit->types.items[i]);
×
6134
      switch ((t->kind = fbuf_get_uint(f))) {
×
6135
      case VCODE_TYPE_INT:
×
6136
      case VCODE_TYPE_OFFSET:
6137
         t->repr = fbuf_get_int(f);
×
6138
         t->low = fbuf_get_int(f);
×
6139
         t->high = fbuf_get_int(f);
×
6140
         break;
×
6141

6142
      case VCODE_TYPE_REAL:
×
6143
         t->rlow = read_double(f);
×
6144
         t->rhigh = read_double(f);
×
6145
         break;
×
6146

6147
      case VCODE_TYPE_CARRAY:
×
6148
      case VCODE_TYPE_UARRAY:
6149
         t->dims = fbuf_get_uint(f);
×
6150
         t->size = fbuf_get_uint(f);
×
6151
         t->elem = fbuf_get_uint(f);
×
6152
         t->bounds = fbuf_get_uint(f);
×
6153
         break;
×
6154

6155
      case VCODE_TYPE_POINTER:
×
6156
      case VCODE_TYPE_ACCESS:
6157
         t->base = fbuf_get_uint(f);
×
6158
         break;
×
6159

6160
      case VCODE_TYPE_FILE:
×
6161
      case VCODE_TYPE_SIGNAL:
6162
      case VCODE_TYPE_RESOLUTION:
6163
      case VCODE_TYPE_CLOSURE:
6164
         t->base = fbuf_get_uint(f);
×
6165
         break;
×
6166

6167
      case VCODE_TYPE_OPAQUE:
6168
      case VCODE_TYPE_DEBUG_LOCUS:
6169
      case VCODE_TYPE_TRIGGER:
6170
         break;
6171

6172
      case VCODE_TYPE_CONTEXT:
×
6173
         t->name = ident_read(ident_rd_ctx);
×
6174
         break;
×
6175

6176
      case VCODE_TYPE_RECORD:
×
6177
         {
6178
            t->name = ident_read(ident_rd_ctx);
×
6179
            vcode_type_array_resize(&(t->fields), fbuf_get_uint(f), 0);
×
6180
            for (unsigned j = 0; j < t->fields.count; j++)
×
6181
               t->fields.items[j] = fbuf_get_uint(f);
×
6182
            break;
6183
         }
6184
      }
6185
   }
×
6186

6187
   var_array_resize(&(unit->vars), fbuf_get_uint(f), 0);
×
6188
   for (unsigned i = 0; i < unit->vars.count; i++) {
×
6189
      var_t *v = &(unit->vars.items[i]);
×
6190
      v->type = fbuf_get_uint(f);
×
6191
      v->bounds = fbuf_get_uint(f);
×
6192
      v->name = ident_read(ident_rd_ctx);
×
6193
      v->flags = fbuf_get_uint(f);
×
6194
   }
6195

6196
   param_array_resize(&(unit->params), fbuf_get_uint(f), 0);
×
6197
   for (unsigned i = 0; i < unit->params.count; i++) {
×
6198
      param_t *p = &(unit->params.items[i]);
×
6199
      p->type = fbuf_get_uint(f);
×
6200
      p->bounds = fbuf_get_uint(f);
×
6201
      p->name = ident_read(ident_rd_ctx);
×
6202
      p->reg = fbuf_get_uint(f);
×
6203
   }
6204

6205
   return unit;
6206
}
6207

6208
vcode_unit_t vcode_read(fbuf_t *f, ident_rd_ctx_t ident_ctx,
×
6209
                        loc_rd_ctx_t *loc_ctx)
6210
{
6211
   const uint8_t version = read_u8(f);
×
6212
   if (version != VCODE_VERSION) {
×
6213
      diag_t *d = diag_new(DIAG_FATAL, NULL);
×
6214
      diag_printf(d, "%s was created with vcode format version %d "
×
6215
                  "(expected %d)", fbuf_file_name(f), version, VCODE_VERSION);
6216
      diag_hint(d, NULL, "this file was most likely created with an earlier "
×
6217
                "version of " PACKAGE_NAME " and should be reanalysed");
6218
      diag_emit(d);
×
6219
      fatal_exit(EXIT_FAILURE);
×
6220
   }
6221

6222
   hash_t *seen = hash_new(128);
×
6223

6224
   vcode_unit_t vu, root = NULL;
×
6225
   while ((vu = vcode_read_unit(f, ident_ctx, loc_ctx, seen))) {
×
6226
      if (root == NULL)
×
6227
         root = vu;
×
6228
   }
6229

6230
   hash_free(seen);
×
6231
   return root;
×
6232
}
6233

6234
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
29,231✔
6235
{
6236
   vcode_select_unit(vu);
29,231✔
6237

6238
   const int nblocks = vcode_count_blocks();
29,231✔
6239
   for (int i = 0; i < nblocks; i++) {
148,968✔
6240
      vcode_select_block(i);
119,737✔
6241

6242
      const int nops = vcode_count_ops();
119,737✔
6243
      for (int op = 0; op < nops; op++) {
1,558,040✔
6244
         switch (vcode_get_op(op)) {
1,438,300✔
6245
         case VCODE_OP_LINK_PACKAGE:
13,449✔
6246
            (*fn)(vcode_get_ident(op), ctx);
13,449✔
6247
            break;
13,449✔
6248
         case VCODE_OP_FCALL:
51,672✔
6249
         case VCODE_OP_PCALL:
6250
         case VCODE_OP_CLOSURE:
6251
         case VCODE_OP_PROTECTED_INIT:
6252
         case VCODE_OP_PACKAGE_INIT:
6253
            {
6254
               const vcode_cc_t cc = vcode_get_subkind(op);
51,672✔
6255
               if (cc != VCODE_CC_FOREIGN && cc != VCODE_CC_VARIADIC)
51,672✔
6256
                  (*fn)(vcode_get_func(op), ctx);
50,629✔
6257
            }
6258
            break;
6259
         default:
6260
            break;
6261
         }
6262
      }
6263
   }
6264
}
29,231✔
6265

6266
#if VCODE_CHECK_UNIONS
6267
#define OP_USE_COUNT_U0(x)                                              \
6268
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6269
#define OP_USE_COUNT_U1(x)                                              \
6270
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6271
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6272
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6273

6274
__attribute__((constructor))
6275
static void vcode_check_unions(void)
6276
{
6277
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6278
   for (int i = 0; i < 256; i++) {
6279
      assert(OP_USE_COUNT_U0(i) <= 1);
6280
      assert(OP_USE_COUNT_U1(i) <= 1);
6281
   }
6282
}
6283
#endif  // VCODE_CHECK_UNIONS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc