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

nickg / nvc / 6410775874

04 Oct 2023 07:25PM UTC coverage: 91.223% (-0.006%) from 91.229%
6410775874

push

github

nickg
Implement LCS2016-032 changes to instance/path name

94 of 94 new or added lines in 3 files covered. (100.0%)

48795 of 53490 relevant lines covered (91.22%)

624869.59 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,983,437✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
205,418✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
38,474✔
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,402,260✔
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,928✔
163
DECLARE_AND_DEFINE_ARRAY(reg);
1,134,800✔
164
DECLARE_AND_DEFINE_ARRAY(block);
114,182✔
165
DECLARE_AND_DEFINE_ARRAY(vtype);
2,157,330✔
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,328✔
229
{
230
   int64_t result;
35,328✔
231
   if (__builtin_sub_overflow(a, b, &result))
35,328✔
232
      return b > 0 ? INT64_MIN : INT64_MAX;
3,925✔
233

234
   return result;
235
}
236

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

243
   return result;
244
}
245

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

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

256
   return reg;
1,134,800✔
257
}
258

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

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

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

275
   block_t *block = vcode_block_data();
1,402,260✔
276

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

283
   return op;
1,402,260✔
284
}
285

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

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

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

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

305
static op_t *vcode_find_definition(vcode_reg_t reg)
1,181,060✔
306
{
307
   for (int i = active_block; i >= 0; i--) {
1,227,570✔
308
      block_t *b = &(active_unit->blocks.items[i]);
1,224,760✔
309
      for (int j = b->ops.count - 1; j >= 0; j--) {
22,372,800✔
310
         if (b->ops.items[j].result == reg)
22,326,300✔
311
            return &(b->ops.items[j]);
1,178,250✔
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,150,240✔
320
{
321
   op_t *defn = vcode_find_definition(reg);
1,150,240✔
322
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
1,150,240✔
323
                what, reg);
324
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
1,150,240✔
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,150,240✔
333
#endif
334

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

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

348
   int depth = MASK_CONTEXT(type);
61,861,600✔
349
   assert(depth <= unit->depth);
61,861,600✔
350
   while (depth != unit->depth)
62,804,000✔
351
      unit = unit->context;
942,468✔
352

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

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

361
   return var_array_nth_ptr(&(active_unit->vars), var);
348,515✔
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)
117,630✔
522
{
523
   state->unit  = active_unit;
117,630✔
524
   state->block = active_block;
117,630✔
525
}
117,630✔
526

527
void vcode_state_restore(const vcode_state_t *state)
134,987✔
528
{
529
   active_unit  = state->unit;
134,987✔
530
   active_block = state->block;
134,987✔
531
}
134,987✔
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)
40,455✔
590
{
591
   assert(active_unit != NULL);
40,455✔
592
   return active_unit->regs.count;
40,455✔
593
}
594

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

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

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

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

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

618
   vtype_t *bounds = vcode_type_data(r->bounds);
705,591✔
619

620
   VCODE_ASSERT(
705,591✔
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) {
705,591✔
625
      if (value) *value = bounds->low;
440,303✔
626
      return true;
440,303✔
627
   }
628
   else
629
      return false;
630
}
631

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

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

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

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

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

649
            switch (o->kind) {
2,631,090✔
650
            case VCODE_OP_FCALL:
58,451✔
651
               if (o->result == VCODE_INVALID_REG)
58,451✔
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,760,380✔
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,760,380✔
694
                  if (false DEBUG_ONLY(|| o->kind != VCODE_OP_CONST)) {
167,972✔
695
                     o->comment = xasprintf("Dead %s definition of r%d",
48,195✔
696
                                            vcode_op_string(o->kind),
697
                                            o->result);
698
                     o->kind = VCODE_OP_COMMENT;
48,195✔
699
                  }
700
                  else
701
                     o->kind = (vcode_op_t)-1;
119,777✔
702
                  vcode_reg_array_resize(&(o->args), 0, VCODE_INVALID_REG);
167,972✔
703
                  pruned++;
167,972✔
704
               }
705
               uses[o->result] = -1;
1,760,380✔
706
               break;
1,760,380✔
707

708
            default:
709
               break;
710
            }
711

712
            for (int k = 0; k < o->args.count; k++) {
7,183,320✔
713
               if (o->args.items[k] != VCODE_INVALID_REG)
4,552,230✔
714
                  uses[o->args.items[k]]++;
4,505,420✔
715
            }
716
         }
717
      }
718
   } while (pruned > 0);
54,234✔
719

720
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
148,966✔
721
      block_t *b = &(active_unit->blocks.items[i]);
114,182✔
722
      op_t *dst = &(b->ops.items[0]);
114,182✔
723
      size_t copied = 0;
114,182✔
724
      for (int j = 0; j < b->ops.count; j++) {
1,516,440✔
725
         const op_t *src = &(b->ops.items[j]);
1,402,260✔
726
         if (src->kind != (vcode_op_t)-1) {
1,402,260✔
727
            if (src != dst) {
1,282,480✔
728
               assert(dst < src);
485,265✔
729
               *dst = *src;
485,265✔
730
            }
731
            dst++;
1,282,480✔
732
            copied++;
1,282,480✔
733
         }
734
      }
735

736
      assert(copied <= b->ops.count);
114,182✔
737
      b->ops.count = copied;
114,182✔
738
   }
739
}
34,784✔
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)
113,771✔
748
{
749
   assert(active_unit != NULL);
113,771✔
750
   return active_unit->blocks.count;
113,771✔
751
}
752

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

760
int vcode_count_vars(void)
80,922✔
761
{
762
   assert(active_unit != NULL);
80,922✔
763
   return active_unit->vars.count;
80,922✔
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)
45,324✔
778
{
779
   return vcode_var_data(var)->name;
45,324✔
780
}
781

782
vcode_type_t vcode_var_type(vcode_var_t var)
154,850✔
783
{
784
   return vcode_var_data(var)->type;
154,850✔
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)
36,310✔
793
{
794
   return vcode_var_data(var)->flags;
36,310✔
795
}
796

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

909
vcode_block_t vcode_get_target(int op, int nth)
126,133✔
910
{
911
   op_t *o = vcode_op_data(op);
126,133✔
912
   assert(OP_HAS_TARGET(o->kind));
126,133✔
913
   return vcode_block_array_nth(&(o->targets), nth);
126,133✔
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,496,700✔
925
{
926
   assert(active_unit != NULL);
1,496,700✔
927
   assert(active_block != VCODE_INVALID_BLOCK);
1,496,700✔
928

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

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

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

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

2331
      switch (at->kind) {
12,222,300✔
2332
      case VCODE_TYPE_INT:
10,429,800✔
2333
         return (at->low == bt->low) && (at->high == bt->high);
19,655,700✔
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:
80,099✔
2337
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
86,232✔
2338
      case VCODE_TYPE_UARRAY:
70,654✔
2339
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
85,439✔
2340
      case VCODE_TYPE_POINTER:
346,091✔
2341
      case VCODE_TYPE_ACCESS:
2342
         return vtype_eq(at->pointed, bt->pointed);
346,091✔
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,925✔
2349
      case VCODE_TYPE_CLOSURE:
2350
      case VCODE_TYPE_SIGNAL:
2351
      case VCODE_TYPE_FILE:
2352
         return vtype_eq(at->base, bt->base);
63,925✔
2353
      case VCODE_TYPE_RECORD:
56,261✔
2354
      case VCODE_TYPE_CONTEXT:
2355
         return at->name == bt->name;
56,261✔
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,455,510✔
2384
{
2385
   assert(active_unit != NULL);
1,455,510✔
2386

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

2392
   switch (bits_for_range(low, high)) {
1,455,510✔
2393
   case 64:
114,520✔
2394
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
114,520✔
2395
      break;
114,520✔
2396
   case 32:
337,519✔
2397
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
337,519✔
2398
      break;
337,519✔
2399
   case 16:
2,440✔
2400
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
2,440✔
2401
      break;
2,440✔
2402
   case 8:
414,152✔
2403
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
414,152✔
2404
      break;
414,152✔
2405
   case 1:
586,876✔
2406
      n->repr = VCODE_REPR_U1;
586,876✔
2407
      break;
586,876✔
2408
   default:
×
2409
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
×
2410
   }
2411

2412
   return vtype_new(n);
1,455,510✔
2413
}
2414

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

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

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

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

2435
   return vtype_new(n);
35,050✔
2436
}
2437

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

2442
   for (int i = 0; i < active_unit->types.count; i++) {
342,081✔
2443
      vtype_t *other = &(active_unit->types.items[i]);
333,677✔
2444
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
333,677✔
2445
         return MAKE_HANDLE(active_unit->depth, i);
16,150✔
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,404✔
2452
                                int nfields)
2453
{
2454
   assert(active_unit != NULL);
8,404✔
2455

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

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

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

2476
   return handle;
8,404✔
2477
}
2478

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

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

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

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

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

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

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

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

2510
   return vtype_new(n);
143,885✔
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,112✔
2525
{
2526
   assert(active_unit != NULL);
25,112✔
2527

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

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

2534
   return vtype_new(n);
25,112✔
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,562✔
2560
{
2561
   assert(active_unit != NULL);
43,562✔
2562
   assert(name != NULL);
43,562✔
2563

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

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

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

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

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

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

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

2592
   return vtype_new(n);
218,321✔
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)
80,343✔
2616
{
2617
   assert(active_unit != NULL);
80,343✔
2618

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

2622
   return vtype_new(n);
80,343✔
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,378,070✔
2648
{
2649
   vtype_t *vt = vcode_type_data(type);
5,378,070✔
2650
   return vt->kind;
5,378,070✔
2651
}
2652

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

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

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

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

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

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

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

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

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

2718
vcode_type_t vtype_pointed(vcode_type_t type)
285,270✔
2719
{
2720
   vtype_t *vt = vcode_type_data(type);
285,270✔
2721
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
285,270✔
2722
   return vt->pointed;
285,270✔
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)
536✔
2740
{
2741
   return vtype_kind(type) == VCODE_TYPE_POINTER
536✔
2742
      && vtype_kind(vtype_pointed(type)) == to;
536✔
2743
}
2744

2745
bool vtype_is_scalar(vcode_type_t type)
281,601✔
2746
{
2747
   const vtype_kind_t kind = vtype_kind(type);
281,601✔
2748
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
281,601✔
2749
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
80,968✔
2750
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
60,157✔
2751
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
57,141✔
2752
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER;
282,998✔
2753
}
2754

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

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

2783
int vtype_repr_bits(vtype_repr_t repr)
409,044✔
2784
{
2785
   switch (repr) {
409,044✔
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)
42,173✔
2796
{
2797
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
42,173✔
2798
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
42,173✔
2799
}
2800

2801
static int64_t vtype_repr_low(vtype_repr_t repr)
7,791✔
2802
{
2803
   switch (repr) {
7,791✔
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,791✔
2818
{
2819
   switch (repr) {
7,791✔
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,791✔
2834
{
2835
   int64_t clamp_low = vtype_repr_low(repr);
7,791✔
2836
   uint64_t clamp_high = vtype_repr_high(repr);
7,791✔
2837

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

2847
int vcode_count_params(void)
9,606✔
2848
{
2849
   assert(active_unit != NULL);
9,606✔
2850
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
9,606✔
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,606✔
2856
}
2857

2858
vcode_type_t vcode_param_type(int param)
25,085✔
2859
{
2860
   assert(active_unit != NULL);
25,085✔
2861
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
25,085✔
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);
25,085✔
2866

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

2870
vcode_reg_t vcode_param_reg(int param)
32,152✔
2871
{
2872
   assert(active_unit != NULL);
32,152✔
2873
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
32,152✔
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);
32,152✔
2878

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

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

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

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

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

2896
   return bnum;
114,182✔
2897
}
2898

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

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

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

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

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

2929
ident_t vcode_unit_name(void)
237,026✔
2930
{
2931
   assert(active_unit != NULL);
237,026✔
2932
   return active_unit->name;
237,026✔
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,348✔
2942
{
2943
   return !!(vu->flags & UNIT_ESCAPING_TLAB);
4,348✔
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)
26,278✔
2962
{
2963
   assert(active_unit != NULL);
26,278✔
2964
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
26,278✔
2965
          || active_unit->kind == VCODE_UNIT_THUNK);
2966
   return active_unit->result;
26,278✔
2967
}
2968

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

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

2981
object_t *vcode_unit_object(vcode_unit_t vu)
48,939✔
2982
{
2983
   assert(vu != NULL);
48,939✔
2984
   return object_from_locus(vu->module, vu->offset, lib_load_handler);
48,939✔
2985
}
2986

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

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

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

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

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

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

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

3027
   return vu;
9,101✔
3028
}
3029

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

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

3041
   vcode_add_child(context, vu);
407✔
3042

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

3047
   return vu;
407✔
3048
}
3049

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

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

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

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

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

3069
   return vu;
7,375✔
3070
}
3071

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

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

3083
   object_locus(obj, &vu->module, &vu->offset);
6,878✔
3084

3085
   if (context != NULL)
6,878✔
3086
      vcode_add_child(context, vu);
3,992✔
3087

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

3092
   return vu;
6,878✔
3093
}
3094

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

3104
   object_locus(obj, &vu->module, &vu->offset);
1,336✔
3105

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

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

3113
   return vu;
1,336✔
3114
}
3115

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

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

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

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

3134
   return vu;
155✔
3135
}
3136

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

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

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

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

3155
   return vu;
48✔
3156
}
3157

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

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

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

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

3176
   return vu;
9,484✔
3177
}
3178

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

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

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

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

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

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

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

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

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

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

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

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

3283
   return op->result;
3284
}
3285

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

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

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

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

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

3312
      return o->result;
27,789✔
3313
   }
3314
}
3315

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

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

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

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

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

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

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

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

3355
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
1,007,160✔
3356
{
3357
   // Reuse any previous constant in this block with the same type and value
3358
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
29,762,600✔
3359
      if (other->kind == VCODE_OP_CONST && other->value == value
8,501,050✔
3360
          && vtype_eq(type, other->type))
887,083✔
3361
         return other->result;
590,847✔
3362
   }
3363

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

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

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

3376
   return op->result;
416,308✔
3377
}
3378

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

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

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

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

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

3401
   // Reuse any previous operation in this block with the same arguments
3402
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,058,890✔
3403
      if (other->args.count != num)
102,873✔
3404
         continue;
57,467✔
3405
      else if (!vtype_eq(vcode_reg_type(other->result), type))
45,406✔
3406
         continue;
423✔
3407

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

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

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

3420
   for (int i = 0; i < num; i++)
1,166,200✔
3421
      vcode_add_arg(op, values[i]);
1,144,310✔
3422

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

3428
#ifdef DEBUG
3429
   vcode_type_t elem = vtype_elem(type);
21,891✔
3430
   for (int i = 0; i < num; i++) {
1,166,200✔
3431
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,144,310✔
3432
                   "wrong element type for item %d", i);
3433
      vcode_assert_const(values[i], "array");
1,144,310✔
3434
   }
3435
#endif
3436

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

3440
   return op->result;
21,891✔
3441
}
3442

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

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

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

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

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

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

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

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

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

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

3486
   for (int i = 0; i < num; i++)
7,043✔
3487
      vcode_add_arg(op, values[i]);
5,280✔
3488

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

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

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

3503
   return op->result;
1,763✔
3504
}
3505

3506
vcode_reg_t emit_address_of(vcode_reg_t value)
28,453✔
3507
{
3508
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
1,129,680✔
3509
      if (other->args.items[0] == value)
104,278✔
3510
         return other->result;
5,139✔
3511
   }
3512

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

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

3520
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
23,314✔
3521
      vcode_type_t elem = vtype_elem(type);
22,020✔
3522
      op->result = vcode_add_reg(vtype_pointer(elem));
22,020✔
3523

3524
      reg_t *rr = vcode_reg_data(op->result);
22,020✔
3525
      rr->bounds = elem;
22,020✔
3526

3527
      return op->result;
22,020✔
3528
   }
3529
   else
3530
      return (op->result = vcode_add_reg(vtype_pointer(type)));
1,294✔
3531
}
3532

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

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

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

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

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

3566
   return var;
36,928✔
3567
}
3568

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

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

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

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

3586
vcode_reg_t emit_load(vcode_var_t var)
45,147✔
3587
{
3588
   // Try scanning backwards through the block for another load or store to
3589
   // this variable
3590
   vcode_reg_t fold = VCODE_INVALID_REG;
45,147✔
3591
   bool aliased = false;
45,147✔
3592
   VCODE_FOR_EACH_OP(other) {
491,106✔
3593
      if (fold == VCODE_INVALID_REG) {
454,547✔
3594
         if (other->kind == VCODE_OP_LOAD && other->address == var)
256,305✔
3595
            fold = other->result;
2,806✔
3596
         else if (other->kind == VCODE_OP_STORE && other->address == var)
253,499✔
3597
            fold = other->args.items[0];
10,171✔
3598
      }
3599

3600
      if (other->kind == VCODE_OP_INDEX && other->address == var)
454,547✔
3601
         aliased = true;
3602
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
454,478✔
3603
         break;   // Nested call captures variables
3604
      else if (other->kind == VCODE_OP_FILE_READ)
445,947✔
3605
         break;   // May write to variable
3606
   }
3607

3608
   var_t *v = vcode_var_data(var);
45,147✔
3609

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

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

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

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

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

3625
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
66,717✔
3626
{
3627
   VCODE_FOR_EACH_OP(other) {
709,825✔
3628
      if (other->kind == VCODE_OP_LOAD_INDIRECT
665,341✔
3629
          && other->args.items[0] == reg) {
92,702✔
3630
         return other->result;
4,987✔
3631
      }
3632
      else if (other->kind == VCODE_OP_FCALL
660,354✔
3633
               || other->kind == VCODE_OP_PCALL
660,354✔
3634
               || other->kind == VCODE_OP_STORE
656,197✔
3635
               || other->kind == VCODE_OP_STORE_INDIRECT
648,317✔
3636
               || other->kind == VCODE_OP_MEMSET
645,774✔
3637
               || other->kind == VCODE_OP_COPY
645,542✔
3638
               || other->kind == VCODE_OP_FILE_READ)
643,120✔
3639
         break;   // May write to this pointer
3640
   }
3641

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

3645
   vcode_type_t rtype = vcode_reg_type(reg);
61,730✔
3646

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

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

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

3655
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
61,730✔
3656

3657
   return op->result;
61,730✔
3658
}
3659

3660
void emit_store(vcode_reg_t reg, vcode_var_t var)
46,838✔
3661
{
3662
   // Any previous store to this variable in this block is dead
3663
   VCODE_FOR_EACH_OP(other) {
786,368✔
3664
      if (other->kind == VCODE_OP_STORE && other->address == var) {
750,221✔
3665
         other->kind = VCODE_OP_COMMENT;
245✔
3666
         other->comment =
490✔
3667
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
245✔
3668
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
245✔
3669
      }
3670
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
749,976✔
3671
         break;   // Needs to get variable for display
3672
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
744,046✔
3673
               && other->address == var)
16,013✔
3674
         break;   // Previous value may be used
3675
   }
3676

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

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

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

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

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

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

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

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

3720
   op->result = vcode_add_reg(vcode_reg_type(lhs));
38,717✔
3721

3722
   vcode_type_t lhs_type = vcode_reg_type(lhs);
38,717✔
3723
   vcode_type_t rhs_type = vcode_reg_type(rhs);
38,717✔
3724

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

3728
   return op->result;
3729
}
3730

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

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

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

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

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

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

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

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

3779
      vbounds = vtype_int(min, max);
1,889✔
3780
   }
3781

3782
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
2,600✔
3783

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

3787
   return reg;
3788
}
3789

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

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

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

3802
   return result;
795✔
3803
}
3804

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

3815
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
546✔
3816

3817
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
546✔
3818

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

3828
   return reg;
3829
}
3830

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

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

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

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

3848
   return result;
535✔
3849
}
3850

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

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

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

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

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

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

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

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

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

3892
   return reg;
3893
}
3894

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

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

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

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

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

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

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

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

3933
   return reg;
3934
}
3935

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

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

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

3948
   return result;
2,663✔
3949
}
3950

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

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

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

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

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

3981
      vbounds = vtype_int(rbl, rbh);
17,664✔
3982
   }
3983

3984
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
17,953✔
3985

3986
   if (vbounds != VCODE_INVALID_TYPE)
17,953✔
3987
      vcode_reg_data(reg)->bounds = vbounds;
17,664✔
3988

3989
   return reg;
3990
}
3991

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

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

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

4004
   return result;
4,485✔
4005
}
4006

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

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

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

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

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

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

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

4059
   vcode_calculate_var_index_type(op, vcode_var_data(var));
13,376✔
4060

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

4065
   return op->result;
13,376✔
4066
}
4067

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

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

4076
   const bool integral =
122,704✔
4077
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
61,352✔
4078
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
61,352✔
4079

4080
   int64_t value;
61,352✔
4081
   if (integral && vcode_reg_const(reg, &value))
61,352✔
4082
      return emit_const(type, value);
12,280✔
4083

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

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

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

4105
   if (from == VCODE_TYPE_INT && bounds == VCODE_INVALID_TYPE) {
38,554✔
4106
      reg_t *rr = vcode_reg_data(op->result);
7,576✔
4107
      rr->bounds = vcode_reg_bounds(reg);
7,576✔
4108
   }
4109
   else if (to == VCODE_TYPE_INT && bounds != VCODE_INVALID_TYPE) {
30,978✔
4110
      reg_t *rr = vcode_reg_data(op->result);
25,163✔
4111
      rr->bounds = bounds;
25,163✔
4112
   }
4113

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4314
   return op->result;
10,530✔
4315
}
4316

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

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

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

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

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

4377
   return result;
4378
}
4379

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4465
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
70,200✔
4466
      ? vtype_pointed(ptr_type) : ptr_type;
35,100✔
4467

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

4471
   return op->result;
35,100✔
4472
}
4473

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

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

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

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

4499
   if (rtype == VCODE_INVALID_TYPE)
38,777✔
4500
      rtype = vtype_offset();
25,300✔
4501

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

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

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

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

4523
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
39,839✔
4524
{
4525
   VCODE_FOR_EACH_OP(other) {
352,457✔
4526
      if (other->kind == VCODE_OP_UARRAY_LEN) {
332,639✔
4527
         if (other->args.items[0] == array && other->dim == dim)
27,810✔
4528
            return other->result;
9,577✔
4529
      }
4530
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
304,829✔
4531
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
10,444✔
4532
                      "array dimension %d out of bounds", dim);
4533

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

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

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

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

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

4555
vcode_reg_t emit_unwrap(vcode_reg_t array)
29,787✔
4556
{
4557
   VCODE_FOR_EACH_OP(other) {
557,243✔
4558
      if (other->kind == VCODE_OP_WRAP && other->result == array)
536,298✔
4559
         return other->args.items[0];
8,157✔
4560
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
528,141✔
4561
         return other->result;
685✔
4562
   }
4563

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

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

4571
   vcode_type_t elem = vt->elem;
20,945✔
4572

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

4576
   op->result = vcode_add_reg(rtype);
20,945✔
4577

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

4581
   return op->result;
20,945✔
4582
}
4583

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

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

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

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

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

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

4626
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
14,490✔
4627
                              vcode_reg_t dir)
4628
{
4629
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_LENGTH) {
401,133✔
4630
      if (other->args.items[0] == left
5,117✔
4631
          && other->args.items[1] == right
4,127✔
4632
          && other->args.items[2] == dir)
3,886✔
4633
         return other->result;
3,886✔
4634
   }
4635

4636
   int64_t lconst, rconst, dconst;
10,604✔
4637
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
10,604✔
4638
       && vcode_reg_const(right, &rconst)) {
6,740✔
4639

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

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

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

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

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

4662
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
37,321✔
4663
{
4664
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
562,035✔
4665
      if (other->hops == hops && other->address == var)
66,888✔
4666
         return other->result;
6,017✔
4667
   }
4668

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

4673
   VCODE_ASSERT(hops > 0, "invalid hop count");
31,304✔
4674

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

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

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

4685
   return op->result;
31,304✔
4686
}
4687

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4867
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
23,853✔
4868
{
4869
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
33,102✔
4870
      if (other->func == name && other->subkind == VCODE_CC_VHDL)
18,578✔
4871
         return other->result;
10,554✔
4872
   }
4873

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4994
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
26,028✔
4995

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

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

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

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

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

5017
   op->result = vcode_add_reg(vtype_pointer(result_type));
26,028✔
5018

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

5022
   return op->result;
26,028✔
5023
}
5024

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

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

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

5044
   op->result = vcode_add_reg(rtype);
26,639✔
5045

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

5049
   return op->result;
26,639✔
5050
}
5051

5052
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
17,217✔
5053
{
5054
   int64_t cconst;
17,217✔
5055
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
17,217✔
5056
       && cconst == 0)
8,115✔
5057
      return;
4,544✔
5058
   else if (dest == src)
17,109✔
5059
      return;
5060

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

5067
   vcode_type_t dtype = vcode_reg_type(dest);
12,673✔
5068
   vcode_type_t stype = vcode_reg_type(src);
12,673✔
5069

5070
   vtype_kind_t dkind = vtype_kind(dtype);
12,673✔
5071
   vtype_kind_t skind = vtype_kind(stype);
12,673✔
5072

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5278
vcode_reg_t emit_null(vcode_type_t type)
5,806✔
5279
{
5280
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
97,265✔
5281
      if (vtype_eq(vcode_reg_type(other->result), type))
1,805✔
5282
         return other->result;
756✔
5283
   }
5284

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

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

5293
   return op->result;
5294
}
5295

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5370
   return op->result;
5371
}
5372

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5431
   return (op->result = vcode_add_reg(vtype_time()));
42✔
5432
}
5433

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

5441
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5442
                "signal argument to last active must have signal type");
5443
   VCODE_ASSERT(len == VCODE_INVALID_REG
36✔
5444
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5445
                "length argument to last active must have offset type");
5446

5447
   return (op->result = vcode_add_reg(vtype_time()));
36✔
5448
}
5449

5450
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,336✔
5451
{
5452
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,336✔
5453
   vcode_add_arg(op, signal);
4,336✔
5454
   vcode_add_arg(op, locus);
4,336✔
5455

5456
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,336✔
5457
                "signal argument must have signal type");
5458
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
4,336✔
5459
                "locus argument must have debug locus type");
5460
}
4,336✔
5461

5462
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
30✔
5463
{
5464
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
30✔
5465
   vcode_add_arg(op, signal);
30✔
5466
   vcode_add_arg(op, len);
30✔
5467

5468
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
30✔
5469
                "signal argument to last active must have signal type");
5470
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
30✔
5471
                "length argument to last active must have offset type");
5472

5473
   return (op->result = vcode_add_reg(vtype_bool()));
30✔
5474
}
5475

5476
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
24✔
5477
{
5478
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
24✔
5479
   vcode_add_arg(op, signal);
24✔
5480
   if (len != VCODE_INVALID_REG)
24✔
5481
      vcode_add_arg(op, len);
3✔
5482

5483
   vcode_type_t signal_type = vcode_reg_type(signal);
24✔
5484

5485
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
24✔
5486
                "signal argument to last active must have signal type");
5487
   VCODE_ASSERT(len == VCODE_INVALID_REG
24✔
5488
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5489
                "length argument to last active must have offset type");
5490

5491
   vcode_type_t base_type = vtype_base(signal_type);
24✔
5492
   op->result = vcode_add_reg(vtype_pointer(base_type));
24✔
5493

5494
   reg_t *rr = vcode_reg_data(op->result);
24✔
5495
   rr->bounds = base_type;
24✔
5496

5497
   return op->result;
24✔
5498
}
5499

5500
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
16,069✔
5501
                       vcode_reg_t dim)
5502
{
5503
   if (rlen == llen)
16,069✔
5504
      return;
5505

5506
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
101,130✔
5507
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
1,790✔
5508
         return;
5509
   }
5510

5511
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
5,132✔
5512
   vcode_add_arg(op, llen);
5,132✔
5513
   vcode_add_arg(op, rlen);
5,132✔
5514
   vcode_add_arg(op, locus);
5,132✔
5515
   if (dim != VCODE_INVALID_REG)
5,132✔
5516
      vcode_add_arg(op, dim);
24✔
5517

5518
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
5,132✔
5519
                "locus argument to length check must be a debug locus");
5520
}
5521

5522
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
535✔
5523
{
5524
   int64_t cval;
535✔
5525
   if (vcode_reg_const(exp, &cval) && cval >= 0)
535✔
5526
      return;
30✔
5527

5528
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
3,078✔
5529
      if (other->args.items[0] == exp)
3✔
5530
         return;
5531
   }
5532

5533
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
505✔
5534
   vcode_add_arg(op, exp);
505✔
5535
   vcode_add_arg(op, locus);
505✔
5536

5537
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
505✔
5538
                "exp argument to exponent check must be a integer");
5539
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
505✔
5540
                "locus argument to exponent check must be a debug locus");
5541
}
5542

5543
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
541✔
5544
{
5545
   int64_t cval;
541✔
5546
   if (vcode_reg_const(denom, &cval) && cval != 0)
541✔
5547
      return;
446✔
5548

5549
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
3,469✔
5550
      if (other->args.items[0] == denom)
56✔
5551
         return;
5552
   }
5553

5554
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
95✔
5555
   vcode_add_arg(op, denom);
95✔
5556
   vcode_add_arg(op, locus);
95✔
5557

5558
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
95✔
5559
                "denom argument to zero check must be a integer");
5560
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
95✔
5561
                "locus argument to zero check must be a debug locus");
5562
}
5563

5564
bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
83,060✔
5565
                            vcode_reg_t right, vcode_reg_t dir)
5566
{
5567
   int64_t dconst;
83,060✔
5568
   if (vcode_reg_const(dir, &dconst)) {
83,060✔
5569
      int64_t lconst, rconst;
76,450✔
5570
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
76,450✔
5571
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
68,791✔
5572
            || (dconst == RANGE_DOWNTO && rconst > lconst);
140,251✔
5573

5574
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
71,460✔
5575

5576
         const bool ok_static =
142,920✔
5577
            (dconst == RANGE_TO
5578
             && bounds->low >= lconst && bounds->high <= rconst)
68,791✔
5579
            || (dconst == RANGE_DOWNTO
8,801✔
5580
                && bounds->low >= rconst && bounds->high <= lconst)
2,669✔
5581
            || (!is_null && (reg == left || reg == right));
77,703✔
5582

5583
         return ok_static;
75,308✔
5584
      }
5585
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
4,990✔
5586
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
4,607✔
5587
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
4,607✔
5588

5589
         assert(lbounds->kind == VCODE_TYPE_REAL);
4,607✔
5590
         assert(rbounds->kind == VCODE_TYPE_REAL);
4,607✔
5591

5592
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
4,607✔
5593
         assert(bounds->kind == VCODE_TYPE_REAL);
4,607✔
5594

5595
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
4,607✔
5596
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
3,848✔
5597
            // Covers the complete double range so can never overflow
5598
            return true;
5599
         }
5600
      }
5601
   }
5602

5603
   return false;
5604
}
5605

5606
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
34,562✔
5607
                              vcode_reg_t left, vcode_reg_t right,
5608
                              vcode_reg_t dir, vcode_reg_t locus,
5609
                              vcode_reg_t hint)
5610
{
5611
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
939,230✔
5612
      if (other->args.items[0] == reg && other->args.items[1] == left
10,883✔
5613
          && other->args.items[2] == right && other->args.items[3] == dir)
208✔
5614
         return;
5615
   }
5616

5617
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
34,354✔
5618
      emit_comment("Elided bounds check for r%d", reg);
22,968✔
5619
      return;
22,968✔
5620
   }
5621

5622
   op_t *op = vcode_add_op(kind);
11,386✔
5623
   vcode_add_arg(op, reg);
11,386✔
5624
   vcode_add_arg(op, left);
11,386✔
5625
   vcode_add_arg(op, right);
11,386✔
5626
   vcode_add_arg(op, dir);
11,386✔
5627
   vcode_add_arg(op, locus);
11,386✔
5628
   vcode_add_arg(op, hint);
11,386✔
5629

5630
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
11,386✔
5631
                "locus argument to bounds check must be a debug locus");
5632
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
11,386✔
5633
                "hint argument to bounds check must be a debug locus");
5634
}
5635

5636
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
2,609✔
5637
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5638
{
5639
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
2,609✔
5640
}
2,609✔
5641

5642
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
31,953✔
5643
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5644
{
5645
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
31,953✔
5646
}
31,953✔
5647

5648
void emit_push_scope(vcode_reg_t locus, vcode_type_t type)
1,061✔
5649
{
5650
   op_t *op = vcode_add_op(VCODE_OP_PUSH_SCOPE);
1,061✔
5651
   vcode_add_arg(op, locus);
1,061✔
5652
   op->type = type;
1,061✔
5653

5654
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,061✔
5655
                "locus argument to push scope must be a debug locus");
5656
}
1,061✔
5657

5658
void emit_pop_scope(void)
1,061✔
5659
{
5660
   vcode_add_op(VCODE_OP_POP_SCOPE);
1,061✔
5661
}
1,061✔
5662

5663
vcode_reg_t emit_debug_locus(ident_t unit, ptrdiff_t offset)
84,509✔
5664
{
5665
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
2,859,310✔
5666
      if (other->ident == unit && other->tag == offset)
320,734✔
5667
         return other->result;
4,209✔
5668
   }
5669

5670
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
80,300✔
5671
   op->ident = unit;
80,300✔
5672
   op->value = offset;
80,300✔
5673

5674
   return (op->result = vcode_add_reg(vtype_debug_locus()));
80,300✔
5675
}
5676

5677
void emit_debug_out(vcode_reg_t reg)
×
5678
{
5679
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
5680
   vcode_add_arg(op, reg);
×
5681
}
×
5682

5683
void emit_cover_stmt(uint32_t tag)
715✔
5684
{
5685
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
715✔
5686
   op->tag = tag;
715✔
5687
}
715✔
5688

5689
void emit_cover_branch(vcode_reg_t test, uint32_t tag, uint32_t flags)
308✔
5690
{
5691
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
308✔
5692
   vcode_add_arg(op, test);
308✔
5693
   op->tag = tag;
308✔
5694
   op->subkind = flags;
308✔
5695
}
308✔
5696

5697
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
281✔
5698
{
5699
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
281✔
5700
   vcode_add_arg(op, signal);
281✔
5701
   op->tag = tag;
281✔
5702
}
281✔
5703

5704
void emit_cover_expr(vcode_reg_t new_mask, uint32_t tag)
318✔
5705
{
5706
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
318✔
5707
   vcode_add_arg(op, new_mask);
318✔
5708
   op->tag = tag;
318✔
5709
}
318✔
5710

5711
void emit_unreachable(vcode_reg_t locus)
153✔
5712
{
5713
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
153✔
5714
   if (locus != VCODE_INVALID_REG)
153✔
5715
      vcode_add_arg(op, locus);
105✔
5716
}
153✔
5717

5718
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
1,290✔
5719
{
5720
   active_unit->flags |= UNIT_UNDEFINED;
1,290✔
5721

5722
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
1,290✔
5723
   op->result = vcode_add_reg(type);
1,290✔
5724
   vcode_reg_data(op->result)->bounds = bounds;
1,290✔
5725

5726
   return op->result;
1,290✔
5727
}
5728

5729
void emit_debug_info(const loc_t *loc)
1,506,870✔
5730
{
5731
   if (!loc_invalid_p(loc))
1,506,870✔
5732
      vcode_block_data()->last_loc = *loc;
1,432,460✔
5733
}
1,506,870✔
5734

5735
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
3,753✔
5736
{
5737
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
131,389✔
5738
      if (other->args.items[0] == context && other->ident == name)
5,773✔
5739
         return other->result;
1,250✔
5740
   }
5741

5742
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
2,503✔
5743
   vcode_add_arg(op, context);
2,503✔
5744
   op->ident = name;
2,503✔
5745

5746
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
2,503✔
5747
                "first argument to link var must be context");
5748

5749
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
2,503✔
5750
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
79✔
5751
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
79✔
5752
   }
5753
   else {
5754
      op->result = vcode_add_reg(vtype_pointer(type));
2,424✔
5755
      vcode_reg_data(op->result)->bounds = type;
2,424✔
5756
   }
5757

5758
   return op->result;
2,503✔
5759
}
5760

5761
vcode_reg_t emit_link_package(ident_t name)
19,593✔
5762
{
5763
   VCODE_FOR_EACH_OP(other) {
771,482✔
5764
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
760,773✔
5765
         return other->result;
5,518✔
5766
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
755,255✔
5767
         return other->result;
3,366✔
5768
   }
5769

5770
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
10,709✔
5771
   op->ident = name;
10,709✔
5772

5773
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
10,709✔
5774

5775
   return (op->result = vcode_add_reg(vtype_context(name)));
10,709✔
5776
}
5777

5778
vcode_reg_t emit_link_instance(ident_t name, vcode_reg_t locus)
108✔
5779
{
5780
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_INSTANCE) {
510✔
5781
      if (other->ident == name)
39✔
5782
         return other->result;
24✔
5783
   }
5784

5785
   op_t *op = vcode_add_op(VCODE_OP_LINK_INSTANCE);
84✔
5786
   vcode_add_arg(op, locus);
84✔
5787
   op->ident = name;
84✔
5788

5789
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
84✔
5790
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
84✔
5791
                "locus argument to link instance must be a debug locus");
5792

5793
   return (op->result = vcode_add_reg(vtype_context(name)));
84✔
5794
}
5795

5796
void emit_enter_state(vcode_reg_t state)
57✔
5797
{
5798
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
549✔
5799
      if (other->args.items[0] == state)
×
5800
         return;
5801
   }
5802

5803
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
57✔
5804
   vcode_add_arg(op, state);
57✔
5805

5806
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
57✔
5807
                "state must have integer type");
5808
}
5809

5810
vcode_reg_t emit_reflect_value(ident_t ptype, vcode_reg_t value,
45✔
5811
                               vcode_reg_t context, vcode_reg_t locus,
5812
                               vcode_reg_t bounds)
5813
{
5814
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
45✔
5815
   vcode_add_arg(op, value);
45✔
5816
   vcode_add_arg(op, context);
45✔
5817
   vcode_add_arg(op, locus);
45✔
5818
   if (bounds != VCODE_INVALID_REG)
45✔
5819
      vcode_add_arg(op, bounds);
6✔
5820

5821
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
45✔
5822
                "invalid reflect value context argument");
5823
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5824
                "locus argument to reflect value must be a debug locus");
5825

5826
   return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype))));
45✔
5827
}
5828

5829
vcode_reg_t emit_reflect_subtype(ident_t ptype, vcode_reg_t context,
42✔
5830
                                 vcode_reg_t locus, vcode_reg_t bounds)
5831
{
5832
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
5833
   vcode_add_arg(op, context);
42✔
5834
   vcode_add_arg(op, locus);
42✔
5835
   if (bounds != VCODE_INVALID_REG)
42✔
5836
      vcode_add_arg(op, bounds);
×
5837

5838
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
5839
                "invalid reflect value context argument");
5840
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
5841
                "locus argument to reflect value must be a debug locus");
5842

5843
   return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype))));
42✔
5844
}
5845

5846
vcode_reg_t emit_function_trigger(vcode_reg_t closure)
12✔
5847
{
5848
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
12✔
5849
   vcode_add_arg(op, closure);
12✔
5850

5851
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
12✔
5852
                "argument to function trigger must be a closure");
5853

5854
   return (op->result = vcode_add_reg(vtype_trigger()));
12✔
5855
}
5856

5857
void emit_add_trigger(vcode_reg_t trigger)
48✔
5858
{
5859
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
48✔
5860
   vcode_add_arg(op, trigger);
48✔
5861

5862
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
48✔
5863
                "add trigger argument must be trigger");
5864
}
48✔
5865

5866
static void vcode_write_unit(vcode_unit_t unit, fbuf_t *f,
×
5867
                             ident_wr_ctx_t ident_wr_ctx,
5868
                             loc_wr_ctx_t *loc_wr_ctx)
5869
{
5870
   write_u8(unit->kind, f);
×
5871
   ident_write(unit->name, ident_wr_ctx);
×
5872
   fbuf_put_int(f, unit->result);
×
5873
   fbuf_put_int(f, unit->flags);
×
5874
   fbuf_put_int(f, unit->depth);
×
5875

5876
   if (unit->offset < 0) {
×
5877
      object_t *obj = object_from_locus(unit->module, unit->offset, NULL);
×
5878
      object_locus(obj, &unit->module, &unit->offset);
×
5879
   }
5880

5881
   ident_write(unit->module, ident_wr_ctx);
×
5882
   fbuf_put_uint(f, unit->offset);
×
5883

5884
   if (unit->context != NULL) {
×
5885
      vcode_select_unit(unit);
×
5886
      vcode_select_unit(vcode_unit_context());
×
5887
      ident_write(vcode_unit_name(), ident_wr_ctx);
×
5888
      vcode_close();
×
5889
   }
5890
   else
5891
      ident_write(NULL, ident_wr_ctx);
×
5892

5893
   fbuf_put_uint(f, unit->blocks.count);
×
5894
   for (unsigned i = 0; i < unit->blocks.count; i++) {
×
5895
      const block_t *b = &(unit->blocks.items[i]);
×
5896
      fbuf_put_uint(f, b->ops.count);
×
5897

5898
      for (unsigned j = 0; j < b->ops.count; j++) {
×
5899
         op_t *op = &(b->ops.items[j]);
×
5900

5901
         if (op->kind == VCODE_OP_DEBUG_LOCUS)
×
5902
            object_fixup_locus(op->ident, &op->value);
×
5903

5904
         fbuf_put_uint(f, op->kind);
×
5905
         fbuf_put_uint(f, op->result);
×
5906
         loc_write(&(op->loc), loc_wr_ctx);
×
5907

5908
         fbuf_put_uint(f, op->args.count);
×
5909
         for (unsigned k = 0; k < op->args.count; k++)
×
5910
            fbuf_put_uint(f, op->args.items[k]);
×
5911

5912
         if (OP_HAS_TARGET(op->kind)) {
×
5913
            fbuf_put_uint(f, op->targets.count);
×
5914
            for (unsigned k = 0; k < op->targets.count; k++)
×
5915
               fbuf_put_uint(f, op->targets.items[k]);
×
5916
         }
5917

5918
         if (OP_HAS_TYPE(op->kind))
×
5919
            fbuf_put_uint(f, op->type);
×
5920
         if (OP_HAS_ADDRESS(op->kind))
×
5921
            fbuf_put_uint(f, op->address);
×
5922
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
×
5923
            ident_write(op->func, ident_wr_ctx);
×
5924
         if (OP_HAS_SUBKIND(op->kind))
×
5925
            fbuf_put_uint(f, op->subkind);
×
5926
         if (OP_HAS_CMP(op->kind))
×
5927
            fbuf_put_uint(f, op->cmp);
×
5928
         if (OP_HAS_VALUE(op->kind))
×
5929
            fbuf_put_int(f, op->value);
×
5930
         if (OP_HAS_REAL(op->kind))
×
5931
            write_double(op->real, f);
×
5932
         if (OP_HAS_COMMENT(op->kind))
×
5933
            ;   // Do not save comments
5934
         if (OP_HAS_DIM(op->kind))
×
5935
            fbuf_put_uint(f, op->dim);
×
5936
         if (OP_HAS_HOPS(op->kind))
×
5937
            fbuf_put_uint(f, op->hops);
×
5938
         if (OP_HAS_FIELD(op->kind))
×
5939
            fbuf_put_uint(f, op->field);
×
5940
         if (OP_HAS_TAG(op->kind))
×
5941
            fbuf_put_uint(f, op->tag);
×
5942
      }
5943
   }
5944

5945
   fbuf_put_uint(f, unit->regs.count);
×
5946
   for (unsigned i = 0; i < unit->regs.count; i++) {
×
5947
      const reg_t *r = &(unit->regs.items[i]);
×
5948
      fbuf_put_uint(f, r->type);
×
5949
      fbuf_put_uint(f, r->bounds);
×
5950
   }
5951

5952
   fbuf_put_uint(f, unit->types.count);
×
5953
   for (unsigned i = 0; i < unit->types.count; i++) {
×
5954
      const vtype_t *t = &(unit->types.items[i]);
×
5955
      fbuf_put_uint(f, t->kind);
×
5956
      switch (t->kind) {
×
5957
      case VCODE_TYPE_INT:
×
5958
      case VCODE_TYPE_OFFSET:
5959
         fbuf_put_int(f, t->repr);
×
5960
         fbuf_put_int(f, t->low);
×
5961
         fbuf_put_int(f, t->high);
×
5962
         break;
×
5963

5964
      case VCODE_TYPE_REAL:
×
5965
         write_double(t->rlow, f);
×
5966
         write_double(t->rhigh, f);
×
5967
         break;
×
5968

5969
      case VCODE_TYPE_CARRAY:
×
5970
      case VCODE_TYPE_UARRAY:
5971
         fbuf_put_uint(f, t->dims);
×
5972
         fbuf_put_uint(f, t->size);
×
5973
         fbuf_put_uint(f, t->elem);
×
5974
         fbuf_put_uint(f, t->bounds);
×
5975
         break;
×
5976

5977
      case VCODE_TYPE_ACCESS:
×
5978
      case VCODE_TYPE_POINTER:
5979
         fbuf_put_uint(f, t->pointed);
×
5980
         break;
×
5981

5982
      case VCODE_TYPE_FILE:
×
5983
      case VCODE_TYPE_SIGNAL:
5984
      case VCODE_TYPE_RESOLUTION:
5985
      case VCODE_TYPE_CLOSURE:
5986
         fbuf_put_uint(f, t->base);
×
5987
         break;
×
5988

5989
      case VCODE_TYPE_OPAQUE:
5990
      case VCODE_TYPE_DEBUG_LOCUS:
5991
      case VCODE_TYPE_TRIGGER:
5992
         break;
5993

5994
      case VCODE_TYPE_CONTEXT:
×
5995
         ident_write(t->name, ident_wr_ctx);
×
5996
         break;
×
5997

5998
      case VCODE_TYPE_RECORD:
×
5999
         ident_write(t->name, ident_wr_ctx);
×
6000
         fbuf_put_uint(f, t->fields.count);
×
6001
         for (unsigned j = 0; j < t->fields.count; j++)
×
6002
            fbuf_put_uint(f, t->fields.items[j]);
×
6003
         break;
6004
      }
6005
   }
×
6006

6007
   fbuf_put_uint(f, unit->vars.count);
×
6008
   for (unsigned i = 0; i < unit->vars.count; i++) {
×
6009
      const var_t *v = &(unit->vars.items[i]);
×
6010
      fbuf_put_uint(f, v->type);
×
6011
      fbuf_put_uint(f, v->bounds);
×
6012
      ident_write(v->name, ident_wr_ctx);
×
6013
      fbuf_put_uint(f, v->flags);
×
6014
   }
6015

6016
   fbuf_put_uint(f, unit->params.count);
×
6017
   for (unsigned i = 0; i < unit->params.count; i++) {
×
6018
      const param_t *p = &(unit->params.items[i]);
×
6019
      fbuf_put_uint(f, p->type);
×
6020
      fbuf_put_uint(f, p->bounds);
×
6021
      ident_write(p->name, ident_wr_ctx);
×
6022
      fbuf_put_uint(f, p->reg);
×
6023
   }
6024

6025
   if (unit->next != NULL)
×
6026
      vcode_write_unit(unit->next, f, ident_wr_ctx, loc_wr_ctx);
×
6027

6028
   if (unit->children != NULL)
×
6029
      vcode_write_unit(unit->children, f, ident_wr_ctx, loc_wr_ctx);
6030
}
×
6031

6032
void vcode_write(vcode_unit_t unit, fbuf_t *f, ident_wr_ctx_t ident_ctx,
×
6033
                 loc_wr_ctx_t *loc_ctx)
6034
{
6035
   assert(unit->context == NULL);
×
6036

6037
   write_u8(VCODE_VERSION, f);
×
6038

6039
   vcode_write_unit(unit, f, ident_ctx, loc_ctx);
×
6040
   write_u8(0xff, f);  // End marker
×
6041
}
×
6042

6043
static vcode_unit_t vcode_read_unit(fbuf_t *f, ident_rd_ctx_t ident_rd_ctx,
×
6044
                                    loc_rd_ctx_t *loc_rd_ctx, hash_t *seen)
6045
{
6046
   const uint8_t marker = read_u8(f);
×
6047
   if (marker == 0xff)
×
6048
      return false;
6049

6050
   vcode_unit_t unit = xcalloc(sizeof(struct _vcode_unit));
×
6051
   unit->kind   = marker;
×
6052
   unit->name   = ident_read(ident_rd_ctx);
×
6053
   unit->result = fbuf_get_int(f);
×
6054
   unit->flags  = fbuf_get_int(f);
×
6055
   unit->depth  = fbuf_get_int(f);
×
6056
   unit->module = ident_read(ident_rd_ctx);
×
6057
   unit->offset = fbuf_get_uint(f);
×
6058

6059
   hash_put(seen, unit->name, unit);
×
6060

6061
   ident_t context_name = ident_read(ident_rd_ctx);
×
6062
   if (context_name != NULL) {
×
6063
      unit->context = hash_get(seen, context_name);
×
6064
      if (unit->context == NULL)
×
6065
         fatal("%s references nonexistent context %s", fbuf_file_name(f),
×
6066
               istr(context_name));
6067

6068
      vcode_add_child(unit->context, unit);
×
6069
   }
6070
   else
6071
      unit->context = NULL;
×
6072

6073
   block_array_resize(&(unit->blocks), fbuf_get_uint(f), 0);
×
6074
   for (unsigned i = 0; i < unit->blocks.count; i++) {
×
6075
      block_t *b = &(unit->blocks.items[i]);
×
6076
      op_array_resize(&(b->ops), fbuf_get_uint(f), 0);
×
6077

6078
      for (unsigned j = 0; j < b->ops.count; j++) {
×
6079
         op_t *op = &(b->ops.items[j]);
×
6080

6081
         op->kind = fbuf_get_uint(f);
×
6082
         op->result = fbuf_get_uint(f);
×
6083
         loc_read(&(op->loc), loc_rd_ctx);
×
6084

6085
         vcode_reg_array_resize(&(op->args), fbuf_get_uint(f), 0);
×
6086
         for (unsigned k = 0; k < op->args.count; k++)
×
6087
            op->args.items[k] = fbuf_get_uint(f);
×
6088

6089
         if (OP_HAS_TARGET(op->kind)) {
×
6090
            vcode_block_array_resize(&(op->targets), fbuf_get_uint(f), 0);
×
6091
            for (unsigned k = 0; k < op->targets.count; k++)
×
6092
               op->targets.items[k] = fbuf_get_uint(f);
×
6093
         }
6094

6095
         if (OP_HAS_TYPE(op->kind))
×
6096
            op->type = fbuf_get_uint(f);
×
6097
         if (OP_HAS_ADDRESS(op->kind))
×
6098
            op->address = fbuf_get_uint(f);
×
6099
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
×
6100
            op->func = ident_read(ident_rd_ctx);
×
6101
         if (OP_HAS_SUBKIND(op->kind))
×
6102
            op->subkind = fbuf_get_uint(f);
×
6103
         if (OP_HAS_CMP(op->kind))
×
6104
            op->cmp = fbuf_get_uint(f);
×
6105
         if (OP_HAS_VALUE(op->kind))
×
6106
            op->value = fbuf_get_int(f);
×
6107
         if (OP_HAS_REAL(op->kind))
×
6108
            op->real = read_double(f);
×
6109
         if (OP_HAS_COMMENT(op->kind))
×
6110
            op->comment = NULL;
×
6111
         if (OP_HAS_DIM(op->kind))
×
6112
            op->dim = fbuf_get_uint(f);
×
6113
         if (OP_HAS_HOPS(op->kind))
×
6114
            op->hops = fbuf_get_uint(f);
×
6115
         if (OP_HAS_FIELD(op->kind))
×
6116
            op->field = fbuf_get_uint(f);
×
6117
         if (OP_HAS_TAG(op->kind))
×
6118
            op->tag = fbuf_get_uint(f);
×
6119
      }
6120
   }
6121

6122
   reg_array_resize(&(unit->regs), fbuf_get_uint(f), 0);
×
6123
   for (unsigned i = 0; i < unit->regs.count; i++) {
×
6124
      reg_t *r = &(unit->regs.items[i]);
×
6125
      r->type = fbuf_get_uint(f);
×
6126
      r->bounds = fbuf_get_uint(f);
×
6127
   }
6128

6129
   vtype_array_resize(&(unit->types), fbuf_get_uint(f), 0);
×
6130
   for (unsigned i = 0; i < unit->types.count; i++) {
×
6131
      vtype_t *t = &(unit->types.items[i]);
×
6132
      switch ((t->kind = fbuf_get_uint(f))) {
×
6133
      case VCODE_TYPE_INT:
×
6134
      case VCODE_TYPE_OFFSET:
6135
         t->repr = fbuf_get_int(f);
×
6136
         t->low = fbuf_get_int(f);
×
6137
         t->high = fbuf_get_int(f);
×
6138
         break;
×
6139

6140
      case VCODE_TYPE_REAL:
×
6141
         t->rlow = read_double(f);
×
6142
         t->rhigh = read_double(f);
×
6143
         break;
×
6144

6145
      case VCODE_TYPE_CARRAY:
×
6146
      case VCODE_TYPE_UARRAY:
6147
         t->dims = fbuf_get_uint(f);
×
6148
         t->size = fbuf_get_uint(f);
×
6149
         t->elem = fbuf_get_uint(f);
×
6150
         t->bounds = fbuf_get_uint(f);
×
6151
         break;
×
6152

6153
      case VCODE_TYPE_POINTER:
×
6154
      case VCODE_TYPE_ACCESS:
6155
         t->base = fbuf_get_uint(f);
×
6156
         break;
×
6157

6158
      case VCODE_TYPE_FILE:
×
6159
      case VCODE_TYPE_SIGNAL:
6160
      case VCODE_TYPE_RESOLUTION:
6161
      case VCODE_TYPE_CLOSURE:
6162
         t->base = fbuf_get_uint(f);
×
6163
         break;
×
6164

6165
      case VCODE_TYPE_OPAQUE:
6166
      case VCODE_TYPE_DEBUG_LOCUS:
6167
      case VCODE_TYPE_TRIGGER:
6168
         break;
6169

6170
      case VCODE_TYPE_CONTEXT:
×
6171
         t->name = ident_read(ident_rd_ctx);
×
6172
         break;
×
6173

6174
      case VCODE_TYPE_RECORD:
×
6175
         {
6176
            t->name = ident_read(ident_rd_ctx);
×
6177
            vcode_type_array_resize(&(t->fields), fbuf_get_uint(f), 0);
×
6178
            for (unsigned j = 0; j < t->fields.count; j++)
×
6179
               t->fields.items[j] = fbuf_get_uint(f);
×
6180
            break;
6181
         }
6182
      }
6183
   }
×
6184

6185
   var_array_resize(&(unit->vars), fbuf_get_uint(f), 0);
×
6186
   for (unsigned i = 0; i < unit->vars.count; i++) {
×
6187
      var_t *v = &(unit->vars.items[i]);
×
6188
      v->type = fbuf_get_uint(f);
×
6189
      v->bounds = fbuf_get_uint(f);
×
6190
      v->name = ident_read(ident_rd_ctx);
×
6191
      v->flags = fbuf_get_uint(f);
×
6192
   }
6193

6194
   param_array_resize(&(unit->params), fbuf_get_uint(f), 0);
×
6195
   for (unsigned i = 0; i < unit->params.count; i++) {
×
6196
      param_t *p = &(unit->params.items[i]);
×
6197
      p->type = fbuf_get_uint(f);
×
6198
      p->bounds = fbuf_get_uint(f);
×
6199
      p->name = ident_read(ident_rd_ctx);
×
6200
      p->reg = fbuf_get_uint(f);
×
6201
   }
6202

6203
   return unit;
6204
}
6205

6206
vcode_unit_t vcode_read(fbuf_t *f, ident_rd_ctx_t ident_ctx,
×
6207
                        loc_rd_ctx_t *loc_ctx)
6208
{
6209
   const uint8_t version = read_u8(f);
×
6210
   if (version != VCODE_VERSION) {
×
6211
      diag_t *d = diag_new(DIAG_FATAL, NULL);
×
6212
      diag_printf(d, "%s was created with vcode format version %d "
×
6213
                  "(expected %d)", fbuf_file_name(f), version, VCODE_VERSION);
6214
      diag_hint(d, NULL, "this file was most likely created with an earlier "
×
6215
                "version of " PACKAGE_NAME " and should be reanalysed");
6216
      diag_emit(d);
×
6217
      fatal_exit(EXIT_FAILURE);
×
6218
   }
6219

6220
   hash_t *seen = hash_new(128);
×
6221

6222
   vcode_unit_t vu, root = NULL;
×
6223
   while ((vu = vcode_read_unit(f, ident_ctx, loc_ctx, seen))) {
×
6224
      if (root == NULL)
×
6225
         root = vu;
×
6226
   }
6227

6228
   hash_free(seen);
×
6229
   return root;
×
6230
}
6231

6232
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
29,209✔
6233
{
6234
   vcode_select_unit(vu);
29,209✔
6235

6236
   const int nblocks = vcode_count_blocks();
29,209✔
6237
   for (int i = 0; i < nblocks; i++) {
148,932✔
6238
      vcode_select_block(i);
119,723✔
6239

6240
      const int nops = vcode_count_ops();
119,723✔
6241
      for (int op = 0; op < nops; op++) {
1,550,330✔
6242
         switch (vcode_get_op(op)) {
1,430,600✔
6243
         case VCODE_OP_LINK_PACKAGE:
13,504✔
6244
            (*fn)(vcode_get_ident(op), ctx);
13,504✔
6245
            break;
13,504✔
6246
         case VCODE_OP_FCALL:
51,751✔
6247
         case VCODE_OP_PCALL:
6248
         case VCODE_OP_CLOSURE:
6249
         case VCODE_OP_PROTECTED_INIT:
6250
         case VCODE_OP_PACKAGE_INIT:
6251
            {
6252
               const vcode_cc_t cc = vcode_get_subkind(op);
51,751✔
6253
               if (cc != VCODE_CC_FOREIGN && cc != VCODE_CC_VARIADIC)
51,751✔
6254
                  (*fn)(vcode_get_func(op), ctx);
50,716✔
6255
            }
6256
            break;
6257
         default:
6258
            break;
6259
         }
6260
      }
6261
   }
6262
}
29,209✔
6263

6264
#if VCODE_CHECK_UNIONS
6265
#define OP_USE_COUNT_U0(x)                                              \
6266
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6267
#define OP_USE_COUNT_U1(x)                                              \
6268
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6269
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6270
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6271

6272
__attribute__((constructor))
6273
static void vcode_check_unions(void)
6274
{
6275
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6276
   for (int i = 0; i < 256; i++) {
6277
      assert(OP_USE_COUNT_U0(i) <= 1);
6278
      assert(OP_USE_COUNT_U1(i) <= 1);
6279
   }
6280
}
6281
#endif  // VCODE_CHECK_UNIONS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc