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

nickg / nvc / 6442205091

07 Oct 2023 04:12PM UTC coverage: 91.159% (-0.008%) from 91.167%
6442205091

push

github

nickg
Add missing ASAN_OPTIONS to GitHub Actions workflow

48740 of 53467 relevant lines covered (91.16%)

592036.67 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);
4,985,063✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
205,424✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
38,486✔
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,407,930✔
109

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

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

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

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

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

161
DECLARE_AND_DEFINE_ARRAY(param);
25,919✔
162
DECLARE_AND_DEFINE_ARRAY(var);
36,860✔
163
DECLARE_AND_DEFINE_ARRAY(reg);
1,138,430✔
164
DECLARE_AND_DEFINE_ARRAY(block);
114,173✔
165
DECLARE_AND_DEFINE_ARRAY(vtype);
2,167,500✔
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,812✔
220
{
221
   int64_t result;
24,812✔
222
   if (__builtin_add_overflow(a, b, &result))
24,812✔
223
      return b < 0 ? INT64_MIN : INT64_MAX;
8,735✔
224

225
   return result;
226
}
227

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

234
   return result;
235
}
236

237
static inline int64_t smul64(int64_t a, int64_t b)
7,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,138,430✔
247
{
248
   assert(active_unit != NULL);
1,138,430✔
249

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

256
   return reg;
1,138,430✔
257
}
258

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

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

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

275
   block_t *block = vcode_block_data();
1,407,930✔
276

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

283
   return op;
1,407,930✔
284
}
285

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

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

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

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

305
static op_t *vcode_find_definition(vcode_reg_t reg)
1,179,610✔
306
{
307
   for (int i = active_block; i >= 0; i--) {
1,226,120✔
308
      block_t *b = &(active_unit->blocks.items[i]);
1,223,310✔
309
      for (int j = b->ops.count - 1; j >= 0; j--) {
22,367,200✔
310
         if (b->ops.items[j].result == reg)
22,320,700✔
311
            return &(b->ops.items[j]);
1,176,800✔
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,148,790✔
320
{
321
   op_t *defn = vcode_find_definition(reg);
1,148,790✔
322
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
1,148,790✔
323
                what, reg);
324
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
1,148,790✔
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,148,790✔
333
#endif
334

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

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

348
   int depth = MASK_CONTEXT(type);
61,459,000✔
349
   assert(depth <= unit->depth);
61,459,000✔
350
   while (depth != unit->depth)
62,364,100✔
351
      unit = unit->context;
905,130✔
352

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

618
   vtype_t *bounds = vcode_type_data(r->bounds);
711,690✔
619

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

624
   if (bounds->low == bounds->high) {
711,690✔
625
      if (value) *value = bounds->low;
446,306✔
626
      return true;
446,306✔
627
   }
628
   else
629
      return false;
630
}
631

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

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

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

643
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
258,740✔
644
         block_t *b = &(active_unit->blocks.items[i]);
204,429✔
645

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

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

708
            default:
709
               break;
710
            }
711

712
            for (int k = 0; k < o->args.count; k++) {
7,201,110✔
713
               if (o->args.items[k] != VCODE_INVALID_REG)
4,554,680✔
714
                  uses[o->args.items[k]]++;
4,507,880✔
715
            }
716
         }
717
      }
718
   } while (pruned > 0);
54,311✔
719

720
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
148,946✔
721
      block_t *b = &(active_unit->blocks.items[i]);
114,173✔
722
      op_t *dst = &(b->ops.items[0]);
114,173✔
723
      size_t copied = 0;
114,173✔
724
      for (int j = 0; j < b->ops.count; j++) {
1,522,100✔
725
         const op_t *src = &(b->ops.items[j]);
1,407,930✔
726
         if (src->kind != (vcode_op_t)-1) {
1,407,930✔
727
            if (src != dst) {
1,287,600✔
728
               assert(dst < src);
491,621✔
729
               *dst = *src;
491,621✔
730
            }
731
            dst++;
1,287,600✔
732
            copied++;
1,287,600✔
733
         }
734
      }
735

736
      assert(copied <= b->ops.count);
114,173✔
737
      b->ops.count = copied;
114,173✔
738
   }
739
}
34,773✔
740

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

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

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

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

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

774
   return VCODE_INVALID_VAR;
775
}
776

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

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

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

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

797
vcode_op_t vcode_get_op(int op)
3,997,860✔
798
{
799
   return vcode_op_data(op)->kind;
3,997,860✔
800
}
801

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

929
   const block_t *b = &(active_unit->blocks.items[active_block]);
1,502,380✔
930
   if (b->ops.count == 0)
1,502,380✔
931
      return false;
932
   else {
933
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,348,500✔
934
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,348,500✔
935
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,348,480✔
936
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
1,348,480✔
937
         || kind == VCODE_OP_UNREACHABLE;
4,034,730✔
938
   }
939
}
940

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

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

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

986
   return printed;
987
}
988

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1113
   return col;
1114
}
1115

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

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

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

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

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

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

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

1168
   dump_callback = callback;
1169
   dump_arg = arg;
1170

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2314
   active_block = old_block;
2315
}
2316
LCOV_EXCL_STOP
2317

2318
bool vtype_eq(vcode_type_t a, vcode_type_t b)
28,868,000✔
2319
{
2320
   assert(active_unit != NULL);
29,278,000✔
2321

2322
   if (a == b)
29,278,000✔
2323
      return true;
2324
   else {
2325
      const vtype_t *at = vcode_type_data(a);
26,865,400✔
2326
      const vtype_t *bt = vcode_type_data(b);
26,865,400✔
2327

2328
      if (at->kind != bt->kind)
26,865,400✔
2329
         return false;
2330

2331
      switch (at->kind) {
12,236,100✔
2332
      case VCODE_TYPE_INT:
10,439,500✔
2333
         return (at->low == bt->low) && (at->high == bt->high);
19,668,800✔
2334
      case VCODE_TYPE_REAL:
910,233✔
2335
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
1,772,270✔
2336
      case VCODE_TYPE_CARRAY:
79,990✔
2337
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
86,111✔
2338
      case VCODE_TYPE_UARRAY:
70,640✔
2339
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
85,425✔
2340
      case VCODE_TYPE_POINTER:
346,097✔
2341
      case VCODE_TYPE_ACCESS:
2342
         return vtype_eq(at->pointed, bt->pointed);
346,097✔
2343
      case VCODE_TYPE_OFFSET:
2344
      case VCODE_TYPE_OPAQUE:
2345
      case VCODE_TYPE_DEBUG_LOCUS:
2346
      case VCODE_TYPE_TRIGGER:
2347
         return true;
2348
      case VCODE_TYPE_RESOLUTION:
63,914✔
2349
      case VCODE_TYPE_CLOSURE:
2350
      case VCODE_TYPE_SIGNAL:
2351
      case VCODE_TYPE_FILE:
2352
         return vtype_eq(at->base, bt->base);
63,914✔
2353
      case VCODE_TYPE_RECORD:
56,233✔
2354
      case VCODE_TYPE_CONTEXT:
2355
         return at->name == bt->name;
56,233✔
2356
      }
2357

2358
      return false;
×
2359
   }
2360
}
2361

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

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

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

2380
   return type;
2381
}
2382

2383
vcode_type_t vtype_int(int64_t low, int64_t high)
1,461,580✔
2384
{
2385
   assert(active_unit != NULL);
1,461,580✔
2386

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

2392
   switch (bits_for_range(low, high)) {
1,461,580✔
2393
   case 64:
114,553✔
2394
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
114,553✔
2395
      break;
114,553✔
2396
   case 32:
341,629✔
2397
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
341,629✔
2398
      break;
341,629✔
2399
   case 16:
2,438✔
2400
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
2,438✔
2401
      break;
2,438✔
2402
   case 8:
413,798✔
2403
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
413,798✔
2404
      break;
413,798✔
2405
   case 1:
589,165✔
2406
      n->repr = VCODE_REPR_U1;
589,165✔
2407
      break;
589,165✔
2408
   default:
×
2409
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
×
2410
   }
2411

2412
   return vtype_new(n);
1,461,580✔
2413
}
2414

2415
vcode_type_t vtype_bool(void)
295,780✔
2416
{
2417
   return vtype_int(0, 1);
295,780✔
2418
}
2419

2420
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
34,984✔
2421
{
2422
   assert(active_unit != NULL);
34,984✔
2423

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

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

2435
   return vtype_new(n);
34,984✔
2436
}
2437

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

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

2448
   return VCODE_INVALID_TYPE;
2449
}
2450

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

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

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

2472
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
8,410✔
2473
   for (int i = 0; i < nfields; i++)
23,448✔
2474
      vcode_type_array_add(&(data->fields), field_types[i]);
15,038✔
2475

2476
   return handle;
8,410✔
2477
}
2478

2479
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
69,955✔
2480
{
2481
   assert(active_unit != NULL);
69,955✔
2482

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

2487
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
69,955✔
2488

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

2496
   return vtype_new(n);
69,955✔
2497
}
2498

2499
vcode_type_t vtype_pointer(vcode_type_t to)
143,847✔
2500
{
2501
   assert(active_unit != NULL);
143,847✔
2502

2503
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
143,847✔
2504
   n->kind    = VCODE_TYPE_POINTER;
143,847✔
2505
   n->pointed = to;
143,847✔
2506

2507
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
143,847✔
2508
                "cannot get pointer to carray type");
2509

2510
   return vtype_new(n);
143,847✔
2511
}
2512

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

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

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

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

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

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

2534
   return vtype_new(n);
25,119✔
2535
}
2536

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

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

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

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

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

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

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

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

2568
   return vtype_new(n);
43,530✔
2569
}
2570

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

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

2579
   return vtype_new(n);
317✔
2580
}
2581

2582
vcode_type_t vtype_offset(void)
219,260✔
2583
{
2584
   assert(active_unit != NULL);
219,260✔
2585

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

2592
   return vtype_new(n);
219,260✔
2593
}
2594

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

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

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

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

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

2615
vcode_type_t vtype_debug_locus(void)
83,689✔
2616
{
2617
   assert(active_unit != NULL);
83,689✔
2618

2619
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
83,689✔
2620
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
83,689✔
2621

2622
   return vtype_new(n);
83,689✔
2623
}
2624

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2745
bool vtype_is_scalar(vcode_type_t type)
281,611✔
2746
{
2747
   const vtype_kind_t kind = vtype_kind(type);
281,611✔
2748
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
281,611✔
2749
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
80,941✔
2750
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
60,127✔
2751
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
57,145✔
2752
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER;
283,008✔
2753
}
2754

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

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

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

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

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

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

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

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

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

2855
   return active_unit->params.count;
9,279✔
2856
}
2857

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

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

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

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

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

2886
   vcode_block_t bnum = active_unit->blocks.count;
114,173✔
2887

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

2891
   if (active_block != VCODE_INVALID_BLOCK)
114,173✔
2892
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
79,400✔
2893
   else
2894
      bptr->last_loc = LOC_INVALID;
34,773✔
2895

2896
   return bnum;
114,173✔
2897
}
2898

2899
void vcode_select_unit(vcode_unit_t unit)
310,871✔
2900
{
2901
   active_unit  = unit;
310,871✔
2902
   active_block = VCODE_INVALID_BLOCK;
310,871✔
2903
}
310,871✔
2904

2905
void vcode_select_block(vcode_block_t block)
510,972✔
2906
{
2907
   assert(active_unit != NULL);
510,972✔
2908
   active_block = block;
510,972✔
2909
}
510,972✔
2910

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

2918
const loc_t *vcode_last_loc(void)
700,779✔
2919
{
2920
   return &(vcode_block_data()->last_loc);
700,779✔
2921
}
2922

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

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

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

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

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

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

2958
   active_unit->result = type;
17,532✔
2959
}
17,532✔
2960

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

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

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

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

2988
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
44,257✔
2989
{
2990
   int hops = 0;
44,257✔
2991
   for (; (unit = unit->context); hops++)
90,616✔
2992
      ;
46,359✔
2993
   return hops;
44,257✔
2994
}
2995

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

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

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

3020
   object_locus(obj, &vu->module, &vu->offset);
9,101✔
3021

3022
   vcode_add_child(context, vu);
9,101✔
3023

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

3028
   return vu;
9,101✔
3029
}
3030

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

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

3042
   vcode_add_child(context, vu);
407✔
3043

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

3048
   return vu;
407✔
3049
}
3050

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

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

3062
   object_locus(obj, &vu->module, &vu->offset);
7,375✔
3063

3064
   vcode_add_child(context, vu);
7,375✔
3065

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

3070
   return vu;
7,375✔
3071
}
3072

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

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

3084
   object_locus(obj, &vu->module, &vu->offset);
6,884✔
3085

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

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

3093
   return vu;
6,884✔
3094
}
3095

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

3105
   object_locus(obj, &vu->module, &vu->offset);
1,319✔
3106

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

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

3114
   return vu;
1,319✔
3115
}
3116

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

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

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

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

3135
   return vu;
155✔
3136
}
3137

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

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

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

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

3156
   return vu;
48✔
3157
}
3158

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

3169
   object_locus(obj, &vu->module, &vu->offset);
9,484✔
3170

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

3174
   vcode_select_unit(vu);
9,484✔
3175
   vcode_select_block(emit_block());
9,484✔
3176

3177
   return vu;
9,484✔
3178
}
3179

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

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

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

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

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

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

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

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

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

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

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

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

3284
   return op->result;
3285
}
3286

3287
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_type_t bounds,
31,056✔
3288
                       vcode_cc_t cc, const vcode_reg_t *args, int nargs)
3289
{
3290
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
31,056✔
3291
   o->func    = func;
31,056✔
3292
   o->type    = type;
31,056✔
3293
   o->subkind = cc;
31,056✔
3294
   for (int i = 0; i < nargs; i++)
118,747✔
3295
      vcode_add_arg(o, args[i]);
87,691✔
3296

3297
   for (int i = 0; i < nargs; i++)
118,747✔
3298
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
87,691✔
3299
                   "invalid argument to function");
3300

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

3305
   if (type == VCODE_INVALID_TYPE)
31,056✔
3306
      return (o->result = VCODE_INVALID_REG);
3,261✔
3307
   else {
3308
      o->result = vcode_add_reg(type);
27,795✔
3309

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

3313
      return o->result;
27,795✔
3314
   }
3315
}
3316

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

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

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

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

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

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

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

3353
   return op->result;
5,612✔
3354
}
3355

3356
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
1,013,640✔
3357
{
3358
   // Reuse any previous constant in this block with the same type and value
3359
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
29,993,200✔
3360
      if (other->kind == VCODE_OP_CONST && other->value == value
8,526,100✔
3361
          && vtype_eq(type, other->type))
898,356✔
3362
         return other->result;
597,070✔
3363
   }
3364

3365
   op_t *op = vcode_add_op(VCODE_OP_CONST);
416,567✔
3366
   op->value  = value;
416,567✔
3367
   op->type   = type;
416,567✔
3368
   op->result = vcode_add_reg(type);
416,567✔
3369

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

3374
   reg_t *r = vcode_reg_data(op->result);
416,567✔
3375
   r->bounds = vtype_int(value, value);
416,567✔
3376

3377
   return op->result;
416,567✔
3378
}
3379

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

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

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

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

3398
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
26,946✔
3399
{
3400
   vtype_kind_t kind = vtype_kind(type);
26,946✔
3401

3402
   // Reuse any previous operation in this block with the same arguments
3403
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,057,430✔
3404
      if (other->args.count != num)
102,822✔
3405
         continue;
57,424✔
3406
      else if (!vtype_eq(vcode_reg_type(other->result), type))
45,398✔
3407
         continue;
419✔
3408

3409
      bool match = true;
3410
      for (int i = 0; match && i < num; i++) {
283,197✔
3411
         if (other->args.items[i] != values[i])
238,218✔
3412
            match = false;
39,878✔
3413
      }
3414

3415
      if (match) return other->result;
44,979✔
3416
   }
3417

3418
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
21,845✔
3419
   op->result = vcode_add_reg(type);
21,845✔
3420

3421
   for (int i = 0; i < num; i++)
1,164,700✔
3422
      vcode_add_arg(op, values[i]);
1,142,860✔
3423

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

3429
#ifdef DEBUG
3430
   vcode_type_t elem = vtype_elem(type);
21,845✔
3431
   for (int i = 0; i < num; i++) {
1,164,700✔
3432
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,142,860✔
3433
                   "wrong element type for item %d", i);
3434
      vcode_assert_const(values[i], "array");
1,142,860✔
3435
   }
3436
#endif
3437

3438
   reg_t *r = vcode_reg_data(op->result);
21,845✔
3439
   r->bounds = vtype_elem(type);
21,845✔
3440

3441
   return op->result;
21,845✔
3442
}
3443

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3507
vcode_reg_t emit_address_of(vcode_reg_t value)
28,404✔
3508
{
3509
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
1,130,230✔
3510
      if (other->args.items[0] == value)
104,227✔
3511
         return other->result;
5,135✔
3512
   }
3513

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

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

3521
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
23,269✔
3522
      vcode_type_t elem = vtype_elem(type);
21,974✔
3523
      op->result = vcode_add_reg(vtype_pointer(elem));
21,974✔
3524

3525
      reg_t *rr = vcode_reg_data(op->result);
21,974✔
3526
      rr->bounds = elem;
21,974✔
3527

3528
      return op->result;
21,974✔
3529
   }
3530
   else
3531
      return (op->result = vcode_add_reg(vtype_pointer(type)));
1,295✔
3532
}
3533

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

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

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

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

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

3567
   return var;
36,860✔
3568
}
3569

3570
vcode_reg_t emit_param(vcode_type_t type, vcode_type_t bounds, ident_t name)
25,919✔
3571
{
3572
   assert(active_unit != NULL);
25,919✔
3573

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

3581
   reg_t *rr = vcode_reg_data(p->reg);
25,919✔
3582
   rr->bounds = bounds;
25,919✔
3583

3584
   return p->reg;
25,919✔
3585
}
3586

3587
vcode_reg_t emit_load(vcode_var_t var)
45,155✔
3588
{
3589
   // Try scanning backwards through the block for another load or store to
3590
   // this variable
3591
   vcode_reg_t fold = VCODE_INVALID_REG;
45,155✔
3592
   bool aliased = false;
45,155✔
3593
   VCODE_FOR_EACH_OP(other) {
505,152✔
3594
      if (fold == VCODE_INVALID_REG) {
468,585✔
3595
         if (other->kind == VCODE_OP_LOAD && other->address == var)
260,110✔
3596
            fold = other->result;
2,806✔
3597
         else if (other->kind == VCODE_OP_STORE && other->address == var)
257,304✔
3598
            fold = other->args.items[0];
10,179✔
3599
      }
3600

3601
      if (other->kind == VCODE_OP_INDEX && other->address == var)
468,585✔
3602
         aliased = true;
3603
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
468,516✔
3604
         break;   // Nested call captures variables
3605
      else if (other->kind == VCODE_OP_FILE_READ)
459,985✔
3606
         break;   // May write to variable
3607
   }
3608

3609
   var_t *v = vcode_var_data(var);
45,155✔
3610

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

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

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

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

3623
   return op->result;
32,203✔
3624
}
3625

3626
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
66,772✔
3627
{
3628
   VCODE_FOR_EACH_OP(other) {
711,172✔
3629
      if (other->kind == VCODE_OP_LOAD_INDIRECT
666,655✔
3630
          && other->args.items[0] == reg) {
92,761✔
3631
         return other->result;
4,993✔
3632
      }
3633
      else if (other->kind == VCODE_OP_FCALL
661,662✔
3634
               || other->kind == VCODE_OP_PCALL
661,662✔
3635
               || other->kind == VCODE_OP_STORE
657,505✔
3636
               || other->kind == VCODE_OP_STORE_INDIRECT
649,614✔
3637
               || other->kind == VCODE_OP_MEMSET
647,071✔
3638
               || other->kind == VCODE_OP_COPY
646,839✔
3639
               || other->kind == VCODE_OP_FILE_READ)
644,412✔
3640
         break;   // May write to this pointer
3641
   }
3642

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

3646
   vcode_type_t rtype = vcode_reg_type(reg);
61,779✔
3647

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

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

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

3656
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
61,779✔
3657

3658
   return op->result;
61,779✔
3659
}
3660

3661
void emit_store(vcode_reg_t reg, vcode_var_t var)
46,783✔
3662
{
3663
   // Any previous store to this variable in this block is dead
3664
   VCODE_FOR_EACH_OP(other) {
805,551✔
3665
      if (other->kind == VCODE_OP_STORE && other->address == var) {
769,459✔
3666
         other->kind = VCODE_OP_COMMENT;
245✔
3667
         other->comment =
490✔
3668
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
245✔
3669
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
245✔
3670
      }
3671
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
769,214✔
3672
         break;   // Needs to get variable for display
3673
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
763,284✔
3674
               && other->address == var)
15,945✔
3675
         break;   // Previous value may be used
3676
   }
3677

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

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

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

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

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

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

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

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

3721
   op->result = vcode_add_reg(vcode_reg_type(lhs));
38,729✔
3722

3723
   vcode_type_t lhs_type = vcode_reg_type(lhs);
38,729✔
3724
   vcode_type_t rhs_type = vcode_reg_type(rhs);
38,729✔
3725

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

3729
   return op->result;
3730
}
3731

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

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

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

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

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

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

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

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

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

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

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

3788
   return reg;
3789
}
3790

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

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

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

3803
   return result;
798✔
3804
}
3805

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

3816
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
548✔
3817

3818
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
548✔
3819

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

3829
   return reg;
3830
}
3831

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

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

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

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

3849
   return result;
538✔
3850
}
3851

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

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

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

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

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

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

3883
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
62✔
3884

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

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

3893
   return reg;
3894
}
3895

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

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

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

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

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

3926
      vbounds = vtype_int(rbl, rbh);
12,406✔
3927
   }
3928

3929
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
12,654✔
3930

3931
   if (vbounds != VCODE_INVALID_TYPE)
12,654✔
3932
      vcode_reg_data(reg)->bounds = vbounds;
12,406✔
3933

3934
   return reg;
3935
}
3936

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

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

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

3949
   return result;
2,663✔
3950
}
3951

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

3965
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
17,970✔
3966
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
17,970✔
3967
      reg_t *lhs_r = vcode_reg_data(lhs);
17,681✔
3968
      reg_t *rhs_r = vcode_reg_data(rhs);
17,681✔
3969

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

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

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

3982
      vbounds = vtype_int(rbl, rbh);
17,681✔
3983
   }
3984

3985
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
17,970✔
3986

3987
   if (vbounds != VCODE_INVALID_TYPE)
17,970✔
3988
      vcode_reg_data(reg)->bounds = vbounds;
17,681✔
3989

3990
   return reg;
3991
}
3992

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

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

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

4005
   return result;
4,500✔
4006
}
4007

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

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

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

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

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

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

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

4060
   vcode_calculate_var_index_type(op, vcode_var_data(var));
13,330✔
4061

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

4066
   return op->result;
13,330✔
4067
}
4068

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

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

4077
   const bool integral =
122,720✔
4078
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
61,360✔
4079
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
61,360✔
4080

4081
   int64_t value;
61,360✔
4082
   if (integral && vcode_reg_const(reg, &value))
61,360✔
4083
      return emit_const(type, value);
12,278✔
4084

4085
   // Try to find a previous cast of this register to this type
4086
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
893,613✔
4087
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
106,818✔
4088
         return other->result;
10,524✔
4089
   }
4090

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

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

4106
   if (from == VCODE_TYPE_INT && bounds == VCODE_INVALID_TYPE) {
38,558✔
4107
      reg_t *rr = vcode_reg_data(op->result);
7,577✔
4108
      rr->bounds = vcode_reg_bounds(reg);
7,577✔
4109
   }
4110
   else if (to == VCODE_TYPE_INT && bounds != VCODE_INVALID_TYPE) {
30,981✔
4111
      reg_t *rr = vcode_reg_data(op->result);
25,166✔
4112
      rr->bounds = bounds;
25,166✔
4113
   }
4114

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

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

4123
void emit_return(vcode_reg_t reg)
42,459✔
4124
{
4125
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
42,459✔
4126
   if (reg != VCODE_INVALID_REG) {
42,459✔
4127
      vcode_add_arg(op, reg);
23,766✔
4128

4129
      const vtype_kind_t rkind = vcode_reg_kind(reg);
23,766✔
4130
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
23,766✔
4131
         vcode_heap_allocate(reg);
7,116✔
4132
         active_unit->flags |= UNIT_ESCAPING_TLAB;
7,116✔
4133
      }
4134

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4275
   return op->result;
221✔
4276
}
4277

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

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

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

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

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

4315
   return op->result;
10,531✔
4316
}
4317

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

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

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

4372
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
6,428✔
4373

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

4378
   return result;
4379
}
4380

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

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

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

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

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

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

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

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

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

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

4427
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
40,322✔
4428
{
4429
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,425,770✔
4430
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
159,981✔
4431
         bool match = true;
4432
         for (int i = 0; match && i < ndims; i++) {
12,698✔
4433
            match = other->args.items[i*3 + 1] == dims[i].left
6,369✔
4434
               && other->args.items[i*3 + 2] == dims[i].right
5,283✔
4435
               && other->args.items[i*3 + 3] == dims[i].dir;
11,628✔
4436
         }
4437
         if (match)
6,329✔
4438
            return other->result;
5,219✔
4439
      }
4440
   }
4441

4442
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
35,103✔
4443
   vcode_add_arg(op, data);
35,103✔
4444
   for (int i = 0; i < ndims; i++) {
70,602✔
4445
      vcode_add_arg(op, dims[i].left);
35,499✔
4446
      vcode_add_arg(op, dims[i].right);
35,499✔
4447
      vcode_add_arg(op, dims[i].dir);
35,499✔
4448
   }
4449

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

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

4466
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
70,206✔
4467
      ? vtype_pointed(ptr_type) : ptr_type;
35,103✔
4468

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

4472
   return op->result;
35,103✔
4473
}
4474

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

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

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

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

4500
   if (rtype == VCODE_INVALID_TYPE)
38,782✔
4501
      rtype = vtype_offset();
25,303✔
4502

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

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

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

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

4524
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
39,936✔
4525
{
4526
   VCODE_FOR_EACH_OP(other) {
353,271✔
4527
      if (other->kind == VCODE_OP_UARRAY_LEN) {
333,450✔
4528
         if (other->args.items[0] == array && other->dim == dim)
27,858✔
4529
            return other->result;
9,620✔
4530
      }
4531
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
305,592✔
4532
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
10,495✔
4533
                      "array dimension %d out of bounds", dim);
4534

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

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

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

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

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

4556
vcode_reg_t emit_unwrap(vcode_reg_t array)
29,791✔
4557
{
4558
   VCODE_FOR_EACH_OP(other) {
558,275✔
4559
      if (other->kind == VCODE_OP_WRAP && other->result == array)
537,329✔
4560
         return other->args.items[0];
8,160✔
4561
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
529,169✔
4562
         return other->result;
685✔
4563
   }
4564

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

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

4572
   vcode_type_t elem = vt->elem;
20,946✔
4573

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

4577
   op->result = vcode_add_reg(rtype);
20,946✔
4578

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

4582
   return op->result;
20,946✔
4583
}
4584

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

4595
   int64_t dir_const;
14,905✔
4596
   if (vcode_reg_const(dir, &dir_const)) {
14,905✔
4597
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
11,005✔
4598
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
11,005✔
4599

4600
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
11,005✔
4601
         return emit_const(vtype_bool(), 1);
41✔
4602
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
10,964✔
4603
         return emit_const(vtype_bool(), 0);
4,933✔
4604
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
6,031✔
4605
         return emit_const(vtype_bool(), 1);
51✔
4606
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
5,980✔
4607
         return emit_const(vtype_bool(), 0);
1,456✔
4608
      else if (dir_const == RANGE_TO)
4,524✔
4609
         return emit_cmp(VCODE_CMP_GT, left, right);
1,213✔
4610
      else
4611
         return emit_cmp(VCODE_CMP_GT, right, left);
3,311✔
4612
   }
4613

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

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

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

4627
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
14,588✔
4628
                              vcode_reg_t dir)
4629
{
4630
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_LENGTH) {
403,194✔
4631
      if (other->args.items[0] == left
5,183✔
4632
          && other->args.items[1] == right
4,159✔
4633
          && other->args.items[2] == dir)
3,915✔
4634
         return other->result;
3,915✔
4635
   }
4636

4637
   int64_t lconst, rconst, dconst;
10,673✔
4638
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
10,673✔
4639
       && vcode_reg_const(right, &rconst)) {
6,780✔
4640

4641
      int64_t diff;
5,359✔
4642
      if (dconst == RANGE_TO)
5,359✔
4643
         diff = rconst - lconst;
3,761✔
4644
      else
4645
         diff = lconst - rconst;
1,598✔
4646

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

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

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

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

4663
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
37,368✔
4664
{
4665
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
568,299✔
4666
      if (other->hops == hops && other->address == var)
66,922✔
4667
         return other->result;
6,025✔
4668
   }
4669

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

4674
   VCODE_ASSERT(hops > 0, "invalid hop count");
31,343✔
4675

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

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

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

4686
   return op->result;
31,343✔
4687
}
4688

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4868
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
23,814✔
4869
{
4870
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
33,014✔
4871
      if (other->func == name && other->subkind == VCODE_CC_VHDL)
18,522✔
4872
         return other->result;
10,547✔
4873
   }
4874

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4995
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
26,042✔
4996

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

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

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

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

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

5018
   op->result = vcode_add_reg(vtype_pointer(result_type));
26,042✔
5019

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

5023
   return op->result;
26,042✔
5024
}
5025

5026
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
27,537✔
5027
{
5028
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
764,446✔
5029
      if (other->args.items[0] == array && other->args.items[1] == offset)
37,572✔
5030
         return other->result;
897✔
5031
   }
5032

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

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

5045
   op->result = vcode_add_reg(rtype);
26,640✔
5046

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

5050
   return op->result;
26,640✔
5051
}
5052

5053
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
17,204✔
5054
{
5055
   int64_t cconst;
17,204✔
5056
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
17,204✔
5057
       && cconst == 0)
8,099✔
5058
      return;
4,536✔
5059
   else if (dest == src)
17,104✔
5060
      return;
5061

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

5068
   vcode_type_t dtype = vcode_reg_type(dest);
12,668✔
5069
   vcode_type_t stype = vcode_reg_type(src);
12,668✔
5070

5071
   vtype_kind_t dkind = vtype_kind(dtype);
12,668✔
5072
   vtype_kind_t skind = vtype_kind(stype);
12,668✔
5073

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5279
vcode_reg_t emit_null(vcode_type_t type)
5,772✔
5280
{
5281
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
96,965✔
5282
      if (vtype_eq(vcode_reg_type(other->result), type))
1,788✔
5283
         return other->result;
739✔
5284
   }
5285

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

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

5294
   return op->result;
5295
}
5296

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5371
   return op->result;
5372
}
5373

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

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

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

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

5392
   vcode_type_t rtype = vtype_base(stype);
10,679✔
5393

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

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

5401
   op->result = vcode_add_reg(vtype_pointer(rtype));
10,679✔
5402

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

5406
   return op->result;
10,679✔
5407
}
5408

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

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

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

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

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

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

5442
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5443
                "signal argument to last active must have signal type");
5444
   VCODE_ASSERT(len == VCODE_INVALID_REG
36✔
5445
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5446
                "length argument to last active must have offset type");
5447

5448
   return (op->result = vcode_add_reg(vtype_time()));
36✔
5449
}
5450

5451
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,337✔
5452
{
5453
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,337✔
5454
   vcode_add_arg(op, signal);
4,337✔
5455
   vcode_add_arg(op, locus);
4,337✔
5456

5457
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,337✔
5458
                "signal argument must have signal type");
5459
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
4,337✔
5460
                "locus argument must have debug locus type");
5461
}
4,337✔
5462

5463
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
30✔
5464
{
5465
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
30✔
5466
   vcode_add_arg(op, signal);
30✔
5467
   vcode_add_arg(op, len);
30✔
5468

5469
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
30✔
5470
                "signal argument to last active must have signal type");
5471
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
30✔
5472
                "length argument to last active must have offset type");
5473

5474
   return (op->result = vcode_add_reg(vtype_bool()));
30✔
5475
}
5476

5477
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
24✔
5478
{
5479
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
24✔
5480
   vcode_add_arg(op, signal);
24✔
5481
   if (len != VCODE_INVALID_REG)
24✔
5482
      vcode_add_arg(op, len);
3✔
5483

5484
   vcode_type_t signal_type = vcode_reg_type(signal);
24✔
5485

5486
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
24✔
5487
                "signal argument to last active must have signal type");
5488
   VCODE_ASSERT(len == VCODE_INVALID_REG
24✔
5489
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5490
                "length argument to last active must have offset type");
5491

5492
   vcode_type_t base_type = vtype_base(signal_type);
24✔
5493
   op->result = vcode_add_reg(vtype_pointer(base_type));
24✔
5494

5495
   reg_t *rr = vcode_reg_data(op->result);
24✔
5496
   rr->bounds = base_type;
24✔
5497

5498
   return op->result;
24✔
5499
}
5500

5501
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
17,370✔
5502
                       vcode_reg_t dim)
5503
{
5504
   if (rlen == llen)
17,370✔
5505
      return;
5506

5507
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
112,130✔
5508
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
1,862✔
5509
         return;
5510
   }
5511

5512
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
5,226✔
5513
   vcode_add_arg(op, llen);
5,226✔
5514
   vcode_add_arg(op, rlen);
5,226✔
5515
   vcode_add_arg(op, locus);
5,226✔
5516
   if (dim != VCODE_INVALID_REG)
5,226✔
5517
      vcode_add_arg(op, dim);
24✔
5518

5519
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
5,226✔
5520
                "locus argument to length check must be a debug locus");
5521
}
5522

5523
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
538✔
5524
{
5525
   int64_t cval;
538✔
5526
   if (vcode_reg_const(exp, &cval) && cval >= 0)
538✔
5527
      return;
33✔
5528

5529
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
3,159✔
5530
      if (other->args.items[0] == exp)
6✔
5531
         return;
5532
   }
5533

5534
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
505✔
5535
   vcode_add_arg(op, exp);
505✔
5536
   vcode_add_arg(op, locus);
505✔
5537

5538
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
505✔
5539
                "exp argument to exponent check must be a integer");
5540
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
505✔
5541
                "locus argument to exponent check must be a debug locus");
5542
}
5543

5544
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
543✔
5545
{
5546
   int64_t cval;
543✔
5547
   if (vcode_reg_const(denom, &cval) && cval != 0)
543✔
5548
      return;
448✔
5549

5550
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
3,469✔
5551
      if (other->args.items[0] == denom)
56✔
5552
         return;
5553
   }
5554

5555
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
95✔
5556
   vcode_add_arg(op, denom);
95✔
5557
   vcode_add_arg(op, locus);
95✔
5558

5559
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
95✔
5560
                "denom argument to zero check must be a integer");
5561
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
95✔
5562
                "locus argument to zero check must be a debug locus");
5563
}
5564

5565
bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
85,091✔
5566
                            vcode_reg_t right, vcode_reg_t dir)
5567
{
5568
   int64_t dconst;
85,091✔
5569
   if (vcode_reg_const(dir, &dconst)) {
85,091✔
5570
      int64_t lconst, rconst;
78,479✔
5571
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
78,479✔
5572
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
70,168✔
5573
            || (dconst == RANGE_DOWNTO && rconst > lconst);
143,657✔
5574

5575
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
73,489✔
5576

5577
         const bool ok_static =
146,978✔
5578
            (dconst == RANGE_TO
5579
             && bounds->low >= lconst && bounds->high <= rconst)
70,168✔
5580
            || (dconst == RANGE_DOWNTO
9,453✔
5581
                && bounds->low >= rconst && bounds->high <= lconst)
3,321✔
5582
            || (!is_null && (reg == left || reg == right));
79,732✔
5583

5584
         return ok_static;
77,337✔
5585
      }
5586
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
4,990✔
5587
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
4,607✔
5588
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
4,607✔
5589

5590
         assert(lbounds->kind == VCODE_TYPE_REAL);
4,607✔
5591
         assert(rbounds->kind == VCODE_TYPE_REAL);
4,607✔
5592

5593
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
4,607✔
5594
         assert(bounds->kind == VCODE_TYPE_REAL);
4,607✔
5595

5596
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
4,607✔
5597
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
3,848✔
5598
            // Covers the complete double range so can never overflow
5599
            return true;
5600
         }
5601
      }
5602
   }
5603

5604
   return false;
5605
}
5606

5607
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
36,620✔
5608
                              vcode_reg_t left, vcode_reg_t right,
5609
                              vcode_reg_t dir, vcode_reg_t locus,
5610
                              vcode_reg_t hint)
5611
{
5612
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,007,780✔
5613
      if (other->args.items[0] == reg && other->args.items[1] == left
10,884✔
5614
          && other->args.items[2] == right && other->args.items[3] == dir)
208✔
5615
         return;
5616
   }
5617

5618
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
36,412✔
5619
      emit_comment("Elided bounds check for r%d", reg);
25,024✔
5620
      return;
25,024✔
5621
   }
5622

5623
   op_t *op = vcode_add_op(kind);
11,388✔
5624
   vcode_add_arg(op, reg);
11,388✔
5625
   vcode_add_arg(op, left);
11,388✔
5626
   vcode_add_arg(op, right);
11,388✔
5627
   vcode_add_arg(op, dir);
11,388✔
5628
   vcode_add_arg(op, locus);
11,388✔
5629
   vcode_add_arg(op, hint);
11,388✔
5630

5631
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
11,388✔
5632
                "locus argument to bounds check must be a debug locus");
5633
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
11,388✔
5634
                "hint argument to bounds check must be a debug locus");
5635
}
5636

5637
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
2,609✔
5638
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5639
{
5640
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
2,609✔
5641
}
2,609✔
5642

5643
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
34,011✔
5644
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5645
{
5646
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
34,011✔
5647
}
34,011✔
5648

5649
void emit_push_scope(vcode_reg_t locus, vcode_type_t type)
1,061✔
5650
{
5651
   op_t *op = vcode_add_op(VCODE_OP_PUSH_SCOPE);
1,061✔
5652
   vcode_add_arg(op, locus);
1,061✔
5653
   op->type = type;
1,061✔
5654

5655
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,061✔
5656
                "locus argument to push scope must be a debug locus");
5657
}
1,061✔
5658

5659
void emit_pop_scope(void)
1,061✔
5660
{
5661
   vcode_add_op(VCODE_OP_POP_SCOPE);
1,061✔
5662
}
1,061✔
5663

5664
vcode_reg_t emit_debug_locus(ident_t unit, ptrdiff_t offset)
87,905✔
5665
{
5666
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
2,997,760✔
5667
      if (other->ident == unit && other->tag == offset)
348,634✔
5668
         return other->result;
4,259✔
5669
   }
5670

5671
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
83,646✔
5672
   op->ident = unit;
83,646✔
5673
   op->value = offset;
83,646✔
5674

5675
   return (op->result = vcode_add_reg(vtype_debug_locus()));
83,646✔
5676
}
5677

5678
void emit_debug_out(vcode_reg_t reg)
×
5679
{
5680
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
5681
   vcode_add_arg(op, reg);
×
5682
}
×
5683

5684
void emit_cover_stmt(uint32_t tag)
715✔
5685
{
5686
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
715✔
5687
   op->tag = tag;
715✔
5688
}
715✔
5689

5690
void emit_cover_branch(vcode_reg_t test, uint32_t tag, uint32_t flags)
308✔
5691
{
5692
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
308✔
5693
   vcode_add_arg(op, test);
308✔
5694
   op->tag = tag;
308✔
5695
   op->subkind = flags;
308✔
5696
}
308✔
5697

5698
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
281✔
5699
{
5700
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
281✔
5701
   vcode_add_arg(op, signal);
281✔
5702
   op->tag = tag;
281✔
5703
}
281✔
5704

5705
void emit_cover_expr(vcode_reg_t new_mask, uint32_t tag)
318✔
5706
{
5707
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
318✔
5708
   vcode_add_arg(op, new_mask);
318✔
5709
   op->tag = tag;
318✔
5710
}
318✔
5711

5712
void emit_unreachable(vcode_reg_t locus)
153✔
5713
{
5714
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
153✔
5715
   if (locus != VCODE_INVALID_REG)
153✔
5716
      vcode_add_arg(op, locus);
105✔
5717
}
153✔
5718

5719
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
1,290✔
5720
{
5721
   active_unit->flags |= UNIT_UNDEFINED;
1,290✔
5722

5723
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
1,290✔
5724
   op->result = vcode_add_reg(type);
1,290✔
5725
   vcode_reg_data(op->result)->bounds = bounds;
1,290✔
5726

5727
   return op->result;
1,290✔
5728
}
5729

5730
void emit_debug_info(const loc_t *loc)
1,513,080✔
5731
{
5732
   if (!loc_invalid_p(loc))
1,513,080✔
5733
      vcode_block_data()->last_loc = *loc;
1,438,720✔
5734
}
1,513,080✔
5735

5736
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
3,753✔
5737
{
5738
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
135,709✔
5739
      if (other->args.items[0] == context && other->ident == name)
5,773✔
5740
         return other->result;
1,250✔
5741
   }
5742

5743
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
2,503✔
5744
   vcode_add_arg(op, context);
2,503✔
5745
   op->ident = name;
2,503✔
5746

5747
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
2,503✔
5748
                "first argument to link var must be context");
5749

5750
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
2,503✔
5751
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
79✔
5752
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
79✔
5753
   }
5754
   else {
5755
      op->result = vcode_add_reg(vtype_pointer(type));
2,424✔
5756
      vcode_reg_data(op->result)->bounds = type;
2,424✔
5757
   }
5758

5759
   return op->result;
2,503✔
5760
}
5761

5762
vcode_reg_t emit_link_package(ident_t name)
19,599✔
5763
{
5764
   VCODE_FOR_EACH_OP(other) {
781,223✔
5765
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
770,514✔
5766
         return other->result;
5,518✔
5767
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
764,996✔
5768
         return other->result;
3,372✔
5769
   }
5770

5771
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
10,709✔
5772
   op->ident = name;
10,709✔
5773

5774
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
10,709✔
5775

5776
   return (op->result = vcode_add_reg(vtype_context(name)));
10,709✔
5777
}
5778

5779
vcode_reg_t emit_link_instance(ident_t name, vcode_reg_t locus)
108✔
5780
{
5781
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_INSTANCE) {
510✔
5782
      if (other->ident == name)
39✔
5783
         return other->result;
24✔
5784
   }
5785

5786
   op_t *op = vcode_add_op(VCODE_OP_LINK_INSTANCE);
84✔
5787
   vcode_add_arg(op, locus);
84✔
5788
   op->ident = name;
84✔
5789

5790
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
84✔
5791
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
84✔
5792
                "locus argument to link instance must be a debug locus");
5793

5794
   return (op->result = vcode_add_reg(vtype_context(name)));
84✔
5795
}
5796

5797
void emit_enter_state(vcode_reg_t state)
57✔
5798
{
5799
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
549✔
5800
      if (other->args.items[0] == state)
×
5801
         return;
5802
   }
5803

5804
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
57✔
5805
   vcode_add_arg(op, state);
57✔
5806

5807
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
57✔
5808
                "state must have integer type");
5809
}
5810

5811
vcode_reg_t emit_reflect_value(ident_t ptype, vcode_reg_t value,
45✔
5812
                               vcode_reg_t context, vcode_reg_t locus,
5813
                               vcode_reg_t bounds)
5814
{
5815
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
45✔
5816
   vcode_add_arg(op, value);
45✔
5817
   vcode_add_arg(op, context);
45✔
5818
   vcode_add_arg(op, locus);
45✔
5819
   if (bounds != VCODE_INVALID_REG)
45✔
5820
      vcode_add_arg(op, bounds);
6✔
5821

5822
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
45✔
5823
                "invalid reflect value context argument");
5824
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5825
                "locus argument to reflect value must be a debug locus");
5826

5827
   return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype))));
45✔
5828
}
5829

5830
vcode_reg_t emit_reflect_subtype(ident_t ptype, vcode_reg_t context,
42✔
5831
                                 vcode_reg_t locus, vcode_reg_t bounds)
5832
{
5833
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
5834
   vcode_add_arg(op, context);
42✔
5835
   vcode_add_arg(op, locus);
42✔
5836
   if (bounds != VCODE_INVALID_REG)
42✔
5837
      vcode_add_arg(op, bounds);
×
5838

5839
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
5840
                "invalid reflect value context argument");
5841
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
5842
                "locus argument to reflect value must be a debug locus");
5843

5844
   return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype))));
42✔
5845
}
5846

5847
vcode_reg_t emit_function_trigger(vcode_reg_t closure)
12✔
5848
{
5849
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
12✔
5850
   vcode_add_arg(op, closure);
12✔
5851

5852
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
12✔
5853
                "argument to function trigger must be a closure");
5854

5855
   return (op->result = vcode_add_reg(vtype_trigger()));
12✔
5856
}
5857

5858
void emit_add_trigger(vcode_reg_t trigger)
48✔
5859
{
5860
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
48✔
5861
   vcode_add_arg(op, trigger);
48✔
5862

5863
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
48✔
5864
                "add trigger argument must be trigger");
5865
}
48✔
5866

5867
static void vcode_write_unit(vcode_unit_t unit, fbuf_t *f,
×
5868
                             ident_wr_ctx_t ident_wr_ctx,
5869
                             loc_wr_ctx_t *loc_wr_ctx)
5870
{
5871
   write_u8(unit->kind, f);
×
5872
   ident_write(unit->name, ident_wr_ctx);
×
5873
   fbuf_put_int(f, unit->result);
×
5874
   fbuf_put_int(f, unit->flags);
×
5875
   fbuf_put_int(f, unit->depth);
×
5876

5877
   if (unit->offset < 0) {
×
5878
      object_t *obj = object_from_locus(unit->module, unit->offset, NULL);
×
5879
      object_locus(obj, &unit->module, &unit->offset);
×
5880
   }
5881

5882
   ident_write(unit->module, ident_wr_ctx);
×
5883
   fbuf_put_uint(f, unit->offset);
×
5884

5885
   if (unit->context != NULL) {
×
5886
      vcode_select_unit(unit);
×
5887
      vcode_select_unit(vcode_unit_context());
×
5888
      ident_write(vcode_unit_name(), ident_wr_ctx);
×
5889
      vcode_close();
×
5890
   }
5891
   else
5892
      ident_write(NULL, ident_wr_ctx);
×
5893

5894
   fbuf_put_uint(f, unit->blocks.count);
×
5895
   for (unsigned i = 0; i < unit->blocks.count; i++) {
×
5896
      const block_t *b = &(unit->blocks.items[i]);
×
5897
      fbuf_put_uint(f, b->ops.count);
×
5898

5899
      for (unsigned j = 0; j < b->ops.count; j++) {
×
5900
         op_t *op = &(b->ops.items[j]);
×
5901

5902
         if (op->kind == VCODE_OP_DEBUG_LOCUS)
×
5903
            object_fixup_locus(op->ident, &op->value);
×
5904

5905
         fbuf_put_uint(f, op->kind);
×
5906
         fbuf_put_uint(f, op->result);
×
5907
         loc_write(&(op->loc), loc_wr_ctx);
×
5908

5909
         fbuf_put_uint(f, op->args.count);
×
5910
         for (unsigned k = 0; k < op->args.count; k++)
×
5911
            fbuf_put_uint(f, op->args.items[k]);
×
5912

5913
         if (OP_HAS_TARGET(op->kind)) {
×
5914
            fbuf_put_uint(f, op->targets.count);
×
5915
            for (unsigned k = 0; k < op->targets.count; k++)
×
5916
               fbuf_put_uint(f, op->targets.items[k]);
×
5917
         }
5918

5919
         if (OP_HAS_TYPE(op->kind))
×
5920
            fbuf_put_uint(f, op->type);
×
5921
         if (OP_HAS_ADDRESS(op->kind))
×
5922
            fbuf_put_uint(f, op->address);
×
5923
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
×
5924
            ident_write(op->func, ident_wr_ctx);
×
5925
         if (OP_HAS_SUBKIND(op->kind))
×
5926
            fbuf_put_uint(f, op->subkind);
×
5927
         if (OP_HAS_CMP(op->kind))
×
5928
            fbuf_put_uint(f, op->cmp);
×
5929
         if (OP_HAS_VALUE(op->kind))
×
5930
            fbuf_put_int(f, op->value);
×
5931
         if (OP_HAS_REAL(op->kind))
×
5932
            write_double(op->real, f);
×
5933
         if (OP_HAS_COMMENT(op->kind))
×
5934
            ;   // Do not save comments
5935
         if (OP_HAS_DIM(op->kind))
×
5936
            fbuf_put_uint(f, op->dim);
×
5937
         if (OP_HAS_HOPS(op->kind))
×
5938
            fbuf_put_uint(f, op->hops);
×
5939
         if (OP_HAS_FIELD(op->kind))
×
5940
            fbuf_put_uint(f, op->field);
×
5941
         if (OP_HAS_TAG(op->kind))
×
5942
            fbuf_put_uint(f, op->tag);
×
5943
      }
5944
   }
5945

5946
   fbuf_put_uint(f, unit->regs.count);
×
5947
   for (unsigned i = 0; i < unit->regs.count; i++) {
×
5948
      const reg_t *r = &(unit->regs.items[i]);
×
5949
      fbuf_put_uint(f, r->type);
×
5950
      fbuf_put_uint(f, r->bounds);
×
5951
   }
5952

5953
   fbuf_put_uint(f, unit->types.count);
×
5954
   for (unsigned i = 0; i < unit->types.count; i++) {
×
5955
      const vtype_t *t = &(unit->types.items[i]);
×
5956
      fbuf_put_uint(f, t->kind);
×
5957
      switch (t->kind) {
×
5958
      case VCODE_TYPE_INT:
×
5959
      case VCODE_TYPE_OFFSET:
5960
         fbuf_put_int(f, t->repr);
×
5961
         fbuf_put_int(f, t->low);
×
5962
         fbuf_put_int(f, t->high);
×
5963
         break;
×
5964

5965
      case VCODE_TYPE_REAL:
×
5966
         write_double(t->rlow, f);
×
5967
         write_double(t->rhigh, f);
×
5968
         break;
×
5969

5970
      case VCODE_TYPE_CARRAY:
×
5971
      case VCODE_TYPE_UARRAY:
5972
         fbuf_put_uint(f, t->dims);
×
5973
         fbuf_put_uint(f, t->size);
×
5974
         fbuf_put_uint(f, t->elem);
×
5975
         fbuf_put_uint(f, t->bounds);
×
5976
         break;
×
5977

5978
      case VCODE_TYPE_ACCESS:
×
5979
      case VCODE_TYPE_POINTER:
5980
         fbuf_put_uint(f, t->pointed);
×
5981
         break;
×
5982

5983
      case VCODE_TYPE_FILE:
×
5984
      case VCODE_TYPE_SIGNAL:
5985
      case VCODE_TYPE_RESOLUTION:
5986
      case VCODE_TYPE_CLOSURE:
5987
         fbuf_put_uint(f, t->base);
×
5988
         break;
×
5989

5990
      case VCODE_TYPE_OPAQUE:
5991
      case VCODE_TYPE_DEBUG_LOCUS:
5992
      case VCODE_TYPE_TRIGGER:
5993
         break;
5994

5995
      case VCODE_TYPE_CONTEXT:
×
5996
         ident_write(t->name, ident_wr_ctx);
×
5997
         break;
×
5998

5999
      case VCODE_TYPE_RECORD:
×
6000
         ident_write(t->name, ident_wr_ctx);
×
6001
         fbuf_put_uint(f, t->fields.count);
×
6002
         for (unsigned j = 0; j < t->fields.count; j++)
×
6003
            fbuf_put_uint(f, t->fields.items[j]);
×
6004
         break;
6005
      }
6006
   }
×
6007

6008
   fbuf_put_uint(f, unit->vars.count);
×
6009
   for (unsigned i = 0; i < unit->vars.count; i++) {
×
6010
      const var_t *v = &(unit->vars.items[i]);
×
6011
      fbuf_put_uint(f, v->type);
×
6012
      fbuf_put_uint(f, v->bounds);
×
6013
      ident_write(v->name, ident_wr_ctx);
×
6014
      fbuf_put_uint(f, v->flags);
×
6015
   }
6016

6017
   fbuf_put_uint(f, unit->params.count);
×
6018
   for (unsigned i = 0; i < unit->params.count; i++) {
×
6019
      const param_t *p = &(unit->params.items[i]);
×
6020
      fbuf_put_uint(f, p->type);
×
6021
      fbuf_put_uint(f, p->bounds);
×
6022
      ident_write(p->name, ident_wr_ctx);
×
6023
      fbuf_put_uint(f, p->reg);
×
6024
   }
6025

6026
   if (unit->next != NULL)
×
6027
      vcode_write_unit(unit->next, f, ident_wr_ctx, loc_wr_ctx);
×
6028

6029
   if (unit->children != NULL)
×
6030
      vcode_write_unit(unit->children, f, ident_wr_ctx, loc_wr_ctx);
6031
}
×
6032

6033
void vcode_write(vcode_unit_t unit, fbuf_t *f, ident_wr_ctx_t ident_ctx,
×
6034
                 loc_wr_ctx_t *loc_ctx)
6035
{
6036
   assert(unit->context == NULL);
×
6037

6038
   write_u8(VCODE_VERSION, f);
×
6039

6040
   vcode_write_unit(unit, f, ident_ctx, loc_ctx);
×
6041
   write_u8(0xff, f);  // End marker
×
6042
}
×
6043

6044
static vcode_unit_t vcode_read_unit(fbuf_t *f, ident_rd_ctx_t ident_rd_ctx,
×
6045
                                    loc_rd_ctx_t *loc_rd_ctx, hash_t *seen)
6046
{
6047
   const uint8_t marker = read_u8(f);
×
6048
   if (marker == 0xff)
×
6049
      return false;
6050

6051
   vcode_unit_t unit = xcalloc(sizeof(struct _vcode_unit));
×
6052
   unit->kind   = marker;
×
6053
   unit->name   = ident_read(ident_rd_ctx);
×
6054
   unit->result = fbuf_get_int(f);
×
6055
   unit->flags  = fbuf_get_int(f);
×
6056
   unit->depth  = fbuf_get_int(f);
×
6057
   unit->module = ident_read(ident_rd_ctx);
×
6058
   unit->offset = fbuf_get_uint(f);
×
6059

6060
   hash_put(seen, unit->name, unit);
×
6061

6062
   ident_t context_name = ident_read(ident_rd_ctx);
×
6063
   if (context_name != NULL) {
×
6064
      unit->context = hash_get(seen, context_name);
×
6065
      if (unit->context == NULL)
×
6066
         fatal("%s references nonexistent context %s", fbuf_file_name(f),
×
6067
               istr(context_name));
6068

6069
      vcode_add_child(unit->context, unit);
×
6070
   }
6071
   else
6072
      unit->context = NULL;
×
6073

6074
   block_array_resize(&(unit->blocks), fbuf_get_uint(f), 0);
×
6075
   for (unsigned i = 0; i < unit->blocks.count; i++) {
×
6076
      block_t *b = &(unit->blocks.items[i]);
×
6077
      op_array_resize(&(b->ops), fbuf_get_uint(f), 0);
×
6078

6079
      for (unsigned j = 0; j < b->ops.count; j++) {
×
6080
         op_t *op = &(b->ops.items[j]);
×
6081

6082
         op->kind = fbuf_get_uint(f);
×
6083
         op->result = fbuf_get_uint(f);
×
6084
         loc_read(&(op->loc), loc_rd_ctx);
×
6085

6086
         vcode_reg_array_resize(&(op->args), fbuf_get_uint(f), 0);
×
6087
         for (unsigned k = 0; k < op->args.count; k++)
×
6088
            op->args.items[k] = fbuf_get_uint(f);
×
6089

6090
         if (OP_HAS_TARGET(op->kind)) {
×
6091
            vcode_block_array_resize(&(op->targets), fbuf_get_uint(f), 0);
×
6092
            for (unsigned k = 0; k < op->targets.count; k++)
×
6093
               op->targets.items[k] = fbuf_get_uint(f);
×
6094
         }
6095

6096
         if (OP_HAS_TYPE(op->kind))
×
6097
            op->type = fbuf_get_uint(f);
×
6098
         if (OP_HAS_ADDRESS(op->kind))
×
6099
            op->address = fbuf_get_uint(f);
×
6100
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
×
6101
            op->func = ident_read(ident_rd_ctx);
×
6102
         if (OP_HAS_SUBKIND(op->kind))
×
6103
            op->subkind = fbuf_get_uint(f);
×
6104
         if (OP_HAS_CMP(op->kind))
×
6105
            op->cmp = fbuf_get_uint(f);
×
6106
         if (OP_HAS_VALUE(op->kind))
×
6107
            op->value = fbuf_get_int(f);
×
6108
         if (OP_HAS_REAL(op->kind))
×
6109
            op->real = read_double(f);
×
6110
         if (OP_HAS_COMMENT(op->kind))
×
6111
            op->comment = NULL;
×
6112
         if (OP_HAS_DIM(op->kind))
×
6113
            op->dim = fbuf_get_uint(f);
×
6114
         if (OP_HAS_HOPS(op->kind))
×
6115
            op->hops = fbuf_get_uint(f);
×
6116
         if (OP_HAS_FIELD(op->kind))
×
6117
            op->field = fbuf_get_uint(f);
×
6118
         if (OP_HAS_TAG(op->kind))
×
6119
            op->tag = fbuf_get_uint(f);
×
6120
      }
6121
   }
6122

6123
   reg_array_resize(&(unit->regs), fbuf_get_uint(f), 0);
×
6124
   for (unsigned i = 0; i < unit->regs.count; i++) {
×
6125
      reg_t *r = &(unit->regs.items[i]);
×
6126
      r->type = fbuf_get_uint(f);
×
6127
      r->bounds = fbuf_get_uint(f);
×
6128
   }
6129

6130
   vtype_array_resize(&(unit->types), fbuf_get_uint(f), 0);
×
6131
   for (unsigned i = 0; i < unit->types.count; i++) {
×
6132
      vtype_t *t = &(unit->types.items[i]);
×
6133
      switch ((t->kind = fbuf_get_uint(f))) {
×
6134
      case VCODE_TYPE_INT:
×
6135
      case VCODE_TYPE_OFFSET:
6136
         t->repr = fbuf_get_int(f);
×
6137
         t->low = fbuf_get_int(f);
×
6138
         t->high = fbuf_get_int(f);
×
6139
         break;
×
6140

6141
      case VCODE_TYPE_REAL:
×
6142
         t->rlow = read_double(f);
×
6143
         t->rhigh = read_double(f);
×
6144
         break;
×
6145

6146
      case VCODE_TYPE_CARRAY:
×
6147
      case VCODE_TYPE_UARRAY:
6148
         t->dims = fbuf_get_uint(f);
×
6149
         t->size = fbuf_get_uint(f);
×
6150
         t->elem = fbuf_get_uint(f);
×
6151
         t->bounds = fbuf_get_uint(f);
×
6152
         break;
×
6153

6154
      case VCODE_TYPE_POINTER:
×
6155
      case VCODE_TYPE_ACCESS:
6156
         t->base = fbuf_get_uint(f);
×
6157
         break;
×
6158

6159
      case VCODE_TYPE_FILE:
×
6160
      case VCODE_TYPE_SIGNAL:
6161
      case VCODE_TYPE_RESOLUTION:
6162
      case VCODE_TYPE_CLOSURE:
6163
         t->base = fbuf_get_uint(f);
×
6164
         break;
×
6165

6166
      case VCODE_TYPE_OPAQUE:
6167
      case VCODE_TYPE_DEBUG_LOCUS:
6168
      case VCODE_TYPE_TRIGGER:
6169
         break;
6170

6171
      case VCODE_TYPE_CONTEXT:
×
6172
         t->name = ident_read(ident_rd_ctx);
×
6173
         break;
×
6174

6175
      case VCODE_TYPE_RECORD:
×
6176
         {
6177
            t->name = ident_read(ident_rd_ctx);
×
6178
            vcode_type_array_resize(&(t->fields), fbuf_get_uint(f), 0);
×
6179
            for (unsigned j = 0; j < t->fields.count; j++)
×
6180
               t->fields.items[j] = fbuf_get_uint(f);
×
6181
            break;
6182
         }
6183
      }
6184
   }
×
6185

6186
   var_array_resize(&(unit->vars), fbuf_get_uint(f), 0);
×
6187
   for (unsigned i = 0; i < unit->vars.count; i++) {
×
6188
      var_t *v = &(unit->vars.items[i]);
×
6189
      v->type = fbuf_get_uint(f);
×
6190
      v->bounds = fbuf_get_uint(f);
×
6191
      v->name = ident_read(ident_rd_ctx);
×
6192
      v->flags = fbuf_get_uint(f);
×
6193
   }
6194

6195
   param_array_resize(&(unit->params), fbuf_get_uint(f), 0);
×
6196
   for (unsigned i = 0; i < unit->params.count; i++) {
×
6197
      param_t *p = &(unit->params.items[i]);
×
6198
      p->type = fbuf_get_uint(f);
×
6199
      p->bounds = fbuf_get_uint(f);
×
6200
      p->name = ident_read(ident_rd_ctx);
×
6201
      p->reg = fbuf_get_uint(f);
×
6202
   }
6203

6204
   return unit;
6205
}
6206

6207
vcode_unit_t vcode_read(fbuf_t *f, ident_rd_ctx_t ident_ctx,
×
6208
                        loc_rd_ctx_t *loc_ctx)
6209
{
6210
   const uint8_t version = read_u8(f);
×
6211
   if (version != VCODE_VERSION) {
×
6212
      diag_t *d = diag_new(DIAG_FATAL, NULL);
×
6213
      diag_printf(d, "%s was created with vcode format version %d "
×
6214
                  "(expected %d)", fbuf_file_name(f), version, VCODE_VERSION);
6215
      diag_hint(d, NULL, "this file was most likely created with an earlier "
×
6216
                "version of " PACKAGE_NAME " and should be reanalysed");
6217
      diag_emit(d);
×
6218
      fatal_exit(EXIT_FAILURE);
×
6219
   }
6220

6221
   hash_t *seen = hash_new(128);
×
6222

6223
   vcode_unit_t vu, root = NULL;
×
6224
   while ((vu = vcode_read_unit(f, ident_ctx, loc_ctx, seen))) {
×
6225
      if (root == NULL)
×
6226
         root = vu;
×
6227
   }
6228

6229
   hash_free(seen);
×
6230
   return root;
×
6231
}
6232

6233
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
29,209✔
6234
{
6235
   vcode_select_unit(vu);
29,209✔
6236

6237
   const int nblocks = vcode_count_blocks();
29,209✔
6238
   for (int i = 0; i < nblocks; i++) {
148,932✔
6239
      vcode_select_block(i);
119,723✔
6240

6241
      const int nops = vcode_count_ops();
119,723✔
6242
      for (int op = 0; op < nops; op++) {
1,557,930✔
6243
         switch (vcode_get_op(op)) {
1,438,210✔
6244
         case VCODE_OP_LINK_PACKAGE:
13,504✔
6245
            (*fn)(vcode_get_ident(op), ctx);
13,504✔
6246
            break;
13,504✔
6247
         case VCODE_OP_FCALL:
51,759✔
6248
         case VCODE_OP_PCALL:
6249
         case VCODE_OP_CLOSURE:
6250
         case VCODE_OP_PROTECTED_INIT:
6251
         case VCODE_OP_PACKAGE_INIT:
6252
            {
6253
               const vcode_cc_t cc = vcode_get_subkind(op);
51,759✔
6254
               if (cc != VCODE_CC_FOREIGN && cc != VCODE_CC_VARIADIC)
51,759✔
6255
                  (*fn)(vcode_get_func(op), ctx);
50,724✔
6256
            }
6257
            break;
6258
         default:
6259
            break;
6260
         }
6261
      }
6262
   }
6263
}
29,209✔
6264

6265
#if VCODE_CHECK_UNIONS
6266
#define OP_USE_COUNT_U0(x)                                              \
6267
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6268
#define OP_USE_COUNT_U1(x)                                              \
6269
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6270
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6271
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6272

6273
__attribute__((constructor))
6274
static void vcode_check_unions(void)
6275
{
6276
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6277
   for (int i = 0; i < 256; i++) {
6278
      assert(OP_USE_COUNT_U0(i) <= 1);
6279
      assert(OP_USE_COUNT_U1(i) <= 1);
6280
   }
6281
}
6282
#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