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

nickg / nvc / 4707550853

pending completion
4707550853

push

github

Nick Gasson
Adjust external test paths

40769 of 45090 relevant lines covered (90.42%)

961143.69 hits per line

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

92.39
/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);
28,331,560✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
1,322,510✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
114,260✔
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 || x == VCODE_OP_STRCONV)
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);
4,329,160✔
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);
399,099✔
162
DECLARE_AND_DEFINE_ARRAY(var);
375,236✔
163
DECLARE_AND_DEFINE_ARRAY(reg);
2,004,713✔
164
DECLARE_AND_DEFINE_ARRAY(block);
522,356✔
165
DECLARE_AND_DEFINE_ARRAY(vtype);
3,266,433✔
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      30
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

217
static hash_t         *registry = NULL;
218
static vcode_dump_fn_t dump_callback = NULL;
219
static void           *dump_arg = NULL;
220

221
static inline int64_t sadd64(int64_t a, int64_t b)
56,884✔
222
{
223
   int64_t result;
56,884✔
224
   if (__builtin_add_overflow(a, b, &result))
56,884✔
225
      return b < 0 ? INT64_MIN : INT64_MAX;
634✔
226

227
   return result;
228
}
229

230
static inline int64_t ssub64(int64_t a, int64_t b)
70,648✔
231
{
232
   int64_t result;
70,648✔
233
   if (__builtin_sub_overflow(a, b, &result))
70,648✔
234
      return b > 0 ? INT64_MIN : INT64_MAX;
736✔
235

236
   return result;
237
}
238

239
static inline int64_t smul64(int64_t a, int64_t b)
22,476✔
240
{
241
   int64_t result;
22,476✔
242
   if (__builtin_mul_overflow(a, b, &result))
22,476✔
243
      return (a > 0 && b > 0) || (a < 0 && b < 0) ? INT64_MAX : INT64_MIN;
796✔
244

245
   return result;
246
}
247

248
static vcode_reg_t vcode_add_reg(vcode_type_t type)
1,682,340✔
249
{
250
   assert(active_unit != NULL);
1,682,340✔
251

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

258
   return reg;
1,682,340✔
259
}
260

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

268
static op_t *vcode_add_op(vcode_op_t kind)
2,087,060✔
269
{
270
   assert(active_unit != NULL);
2,087,060✔
271
   assert(active_block != VCODE_INVALID_BLOCK);
2,087,060✔
272

273
   VCODE_ASSERT(
2,087,060✔
274
      !vcode_block_finished(),
275
      "attempt to add to already finished block %d", active_block);
276

277
   block_t *block = vcode_block_data();
2,087,060✔
278

279
   op_t *op = op_array_alloc(&(block->ops));
2,087,060✔
280
   memset(op, '\0', sizeof(op_t));
2,087,060✔
281
   op->kind   = kind;
2,087,060✔
282
   op->result = VCODE_INVALID_REG;
2,087,060✔
283
   op->loc    = block->last_loc;
2,087,060✔
284

285
   return op;
2,087,060✔
286
}
287

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

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

298
static op_t *vcode_op_data(int op)
8,808,950✔
299
{
300
   assert(active_unit != NULL);
8,808,950✔
301
   assert(active_block != VCODE_INVALID_BLOCK);
8,808,950✔
302

303
   block_t *b = &(active_unit->blocks.items[active_block]);
8,808,950✔
304
   return op_array_nth_ptr(&(b->ops), op);
8,808,950✔
305
}
306

307
static op_t *vcode_find_definition(vcode_reg_t reg)
41,220✔
308
{
309
   for (int i = active_block; i >= 0; i--) {
100,232✔
310
      block_t *b = &(active_unit->blocks.items[i]);
96,792✔
311
      for (int j = b->ops.count - 1; j >= 0; j--) {
989,027✔
312
         if (b->ops.items[j].result == reg)
930,015✔
313
            return &(b->ops.items[j]);
37,780✔
314
      }
315
   }
316

317
   return NULL;
318
}
319

320
static reg_t *vcode_reg_data(vcode_reg_t reg)
7,659,130✔
321
{
322
   assert(active_unit != NULL);
7,659,130✔
323
   assert(reg != VCODE_INVALID_REG);
7,659,130✔
324
   return reg_array_nth_ptr(&(active_unit->regs), reg);
7,659,130✔
325
}
326

327
static vtype_t *vcode_type_data(vcode_type_t type)
69,414,900✔
328
{
329
   assert(type != VCODE_INVALID_TYPE);
69,414,900✔
330
   assert(active_unit != NULL);
69,414,900✔
331
   vcode_unit_t unit = active_unit;
69,414,900✔
332

333
   int depth = MASK_CONTEXT(type);
69,414,900✔
334
   assert(depth <= unit->depth);
69,414,900✔
335
   while (depth != unit->depth)
70,335,600✔
336
      unit = unit->context;
920,755✔
337

338
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
69,414,900✔
339
}
340

341
static var_t *vcode_var_data(vcode_var_t var)
390,332✔
342
{
343
   assert(active_unit != NULL);
390,332✔
344
   assert(var != VCODE_INVALID_VAR);
390,332✔
345

346
   return var_array_nth_ptr(&(active_unit->vars), var);
390,332✔
347
}
348

349
void vcode_heap_allocate(vcode_reg_t reg)
35,567✔
350
{
351
   op_t *defn = vcode_find_definition(reg);
35,567✔
352
   if (defn == NULL) {
35,567✔
353
      // It is always safe to return a pointer to an argument
354
      return;
355
   }
356

357
   switch (defn->kind) {
32,127✔
358
   case VCODE_OP_CONST:
359
   case VCODE_OP_CONST_REAL:
360
   case VCODE_OP_CONST_ARRAY:
361
   case VCODE_OP_CONST_REP:
362
   case VCODE_OP_NULL:
363
   case VCODE_OP_UNDEFINED:
364
   case VCODE_OP_ADDRESS_OF:
365
   case VCODE_OP_LINK_VAR:
366
   case VCODE_OP_LINK_PACKAGE:
367
      break;
368

369
   case VCODE_OP_ALLOC:
370
      // Always allocated in mspace
371
      break;
372

373
   case VCODE_OP_INDEX:
3,458✔
374
      vcode_var_data(defn->address)->flags |= VAR_HEAP;
3,458✔
375
      active_unit->flags |= UNIT_ESCAPING_TLAB;
3,458✔
376
      break;
3,458✔
377

378
   case VCODE_OP_VAR_UPREF:
1,896✔
379
      {
380
         vcode_state_t state;
1,896✔
381
         vcode_state_save(&state);
1,896✔
382

383
         for (int i = 0; i < defn->hops; i++)
3,792✔
384
            vcode_select_unit(vcode_unit_context());
1,896✔
385

386
         vcode_var_data(defn->address)->flags |= VAR_HEAP;
1,896✔
387
         active_unit->flags |= UNIT_ESCAPING_TLAB;
1,896✔
388

389
         vcode_state_restore(&state);
1,896✔
390
      }
391
      break;
1,896✔
392

393
   case VCODE_OP_ARRAY_REF:
370✔
394
      vcode_heap_allocate(defn->args.items[0]);
370✔
395
      break;
370✔
396

397
   case VCODE_OP_WRAP:
10,153✔
398
   case VCODE_OP_UNWRAP:
399
   case VCODE_OP_RESOLVED:
400
      vcode_heap_allocate(defn->args.items[0]);
10,153✔
401
      break;
10,153✔
402

403
   case VCODE_OP_LAST_VALUE:
404
      // Returns a pointer into the C heap
405
      break;
406

407
   case VCODE_OP_CONVSTR:
408
      // Runtime code allocates in mspace
409
      break;
410

411
   case VCODE_OP_LOAD:
3,264✔
412
      {
413
         if (vcode_reg_kind(reg) != VCODE_TYPE_UARRAY)
3,264✔
414
            return;
415

416
         // Any store to this variable must be heap allocated
417
         for (int i = 0; i < active_unit->blocks.count; i++) {
35,886✔
418
            block_t *b = &(active_unit->blocks.items[i]);
33,788✔
419
            for (int j = 0; j < b->ops.count; j++) {
558,576✔
420
               op_t *op = &(b->ops.items[j]);
524,788✔
421
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
524,788✔
422
                  vcode_heap_allocate(op->args.items[0]);
2,098✔
423

424
               VCODE_ASSERT(
524,788✔
425
                  op->kind != VCODE_OP_INDEX || op->address != defn->address,
426
                  "cannot heap allocate aliased pointer r%d", reg);
427
            }
428
         }
429
      }
430
      break;
431

432
   case VCODE_OP_FCALL:
433
      // Must have been safety checked by definition
434
      break;
435

436
   case VCODE_OP_RECORD_REF:
24✔
437
      vcode_heap_allocate(defn->args.items[0]);
24✔
438
      break;
24✔
439

440
   case VCODE_OP_SELECT:
494✔
441
      vcode_heap_allocate(defn->args.items[1]);
494✔
442
      vcode_heap_allocate(defn->args.items[2]);
494✔
443
      break;
494✔
444

445
   case VCODE_OP_LOAD_INDIRECT:
450✔
446
      {
447
         // Always OK if scalar otherwise check the pointer source
448
         const vtype_kind_t vtkind = vcode_reg_kind(reg);
450✔
449
         if (vtkind != VCODE_TYPE_INT && vtkind != VCODE_TYPE_REAL)
450✔
450
            vcode_heap_allocate(defn->args.items[0]);
278✔
451
      }
452
      break;
453

454
   case VCODE_OP_ALL:
455
      // Must have been allocated on the heap
456
      break;
457

458
   case VCODE_OP_NEW:
459
      // On the heap by definition
460
      break;
461

462
   case VCODE_OP_SUB:
463
   case VCODE_OP_MUL:
464
   case VCODE_OP_DIV:
465
   case VCODE_OP_CAST:
466
   case VCODE_OP_CMP:
467
   case VCODE_OP_OR:
468
   case VCODE_OP_NOT:
469
   case VCODE_OP_AND:
470
   case VCODE_OP_NOR:
471
   case VCODE_OP_NAND:
472
   case VCODE_OP_XOR:
473
   case VCODE_OP_XNOR:
474
   case VCODE_OP_EVENT:
475
   case VCODE_OP_ACTIVE:
476
   case VCODE_OP_UARRAY_LEN:
477
   case VCODE_OP_UARRAY_LEFT:
478
   case VCODE_OP_UARRAY_RIGHT:
479
   case VCODE_OP_UARRAY_DIR:
480
   case VCODE_OP_LAST_EVENT:
481
   case VCODE_OP_NEG:
482
   case VCODE_OP_EXP:
483
   case VCODE_OP_ABS:
484
   case VCODE_OP_MOD:
485
   case VCODE_OP_REM:
486
   case VCODE_OP_ENDFILE:
487
   case VCODE_OP_ADD:
488
   case VCODE_OP_TRAP_ADD:
489
   case VCODE_OP_TRAP_SUB:
490
   case VCODE_OP_TRAP_MUL:
491
   case VCODE_OP_TRAP_NEG:
492
   case VCODE_OP_TRAP_EXP:
493
      // Result cannot reference pointer
494
      break;
495

496
   default:
497
      VCODE_ASSERT(false, "cannot heap allocate r%d", reg);
×
498
   }
499
}
500

501
void vcode_state_save(vcode_state_t *state)
132,499✔
502
{
503
   state->unit  = active_unit;
132,499✔
504
   state->block = active_block;
132,499✔
505
}
132,499✔
506

507
void vcode_state_restore(const vcode_state_t *state)
144,385✔
508
{
509
   active_unit  = state->unit;
144,385✔
510
   active_block = state->block;
144,385✔
511
}
144,385✔
512

513
void vcode_unit_unref(vcode_unit_t unit)
15,097✔
514
{
515
   assert(unit != NULL);
15,097✔
516

517
   if (unit == active_unit)
15,097✔
518
      vcode_close();
14,843✔
519

520
   while (unit->children)
15,129✔
521
      vcode_unit_unref(unit->children);
32✔
522

523
   if (unit->context != NULL) {
15,097✔
524
      vcode_unit_t *it = &(unit->context->children);
128✔
525
      for (; *it != NULL && *it != unit; it = &((*it)->next))
412✔
526
         ;
284✔
527
      assert(*it != NULL);
128✔
528
      *it = (*it)->next;
128✔
529
   }
530

531
   if (unit->name != NULL)
15,097✔
532
      hash_delete(registry, unit->name);
36✔
533

534
   for (unsigned i = 0; i < unit->blocks.count; i++) {
30,290✔
535
      block_t *b = &(unit->blocks.items[i]);
15,193✔
536

537
      for (unsigned j = 0; j < b->ops.count; j++) {
73,480✔
538
         op_t *o = &(b->ops.items[j]);
58,287✔
539
         if (OP_HAS_COMMENT(o->kind))
58,287✔
540
            free(o->comment);
8,149✔
541
         if (OP_HAS_TARGET(o->kind))
58,287✔
542
            free(o->targets.items);
72✔
543
         free(o->args.items);
58,287✔
544
      }
545
      free(b->ops.items);
15,193✔
546
   }
547
   free(unit->blocks.items);
15,097✔
548

549
   for (unsigned i = 0; i < unit->types.count; i++) {
84,525✔
550
      vtype_t *vt = &(unit->types.items[i]);
69,428✔
551
      if (vt->kind == VCODE_TYPE_RECORD)
69,428✔
552
         free(vt->fields.items);
98✔
553
   }
554
   free(unit->types.items);
15,097✔
555

556
   free(unit->regs.items);
15,097✔
557
   free(unit->vars.items);
15,097✔
558
   free(unit->params.items);
15,097✔
559
   free(unit);
15,097✔
560
}
15,097✔
561

562
vcode_unit_t vcode_unit_next(vcode_unit_t unit)
12,215✔
563
{
564
   return unit->next;
12,215✔
565
}
566

567
vcode_unit_t vcode_unit_child(vcode_unit_t unit)
38,897✔
568
{
569
   return unit->children;
38,897✔
570
}
571

572
int vcode_count_regs(void)
45,711✔
573
{
574
   assert(active_unit != NULL);
45,711✔
575
   return active_unit->regs.count;
45,711✔
576
}
577

578
vcode_type_t vcode_reg_type(vcode_reg_t reg)
4,969,360✔
579
{
580
   return vcode_reg_data(reg)->type;
4,969,360✔
581
}
582

583
vtype_kind_t vcode_reg_kind(vcode_reg_t reg)
1,419,290✔
584
{
585
   return vtype_kind(vcode_reg_type(reg));
1,419,290✔
586
}
587

588
vcode_type_t vcode_reg_bounds(vcode_reg_t reg)
196,254✔
589
{
590
   return vcode_reg_data(reg)->bounds;
196,254✔
591
}
592

593
bool vcode_reg_const(vcode_reg_t reg, int64_t *value)
971,268✔
594
{
595
   reg_t *r = vcode_reg_data(reg);
971,268✔
596

597
   vtype_kind_t kind = vtype_kind(r->type);
971,268✔
598
   if (kind != VCODE_TYPE_INT && kind != VCODE_TYPE_OFFSET)
971,268✔
599
      return false;
600

601
   vtype_t *bounds = vcode_type_data(r->bounds);
961,799✔
602

603
   VCODE_ASSERT(
961,799✔
604
      bounds->kind == VCODE_TYPE_INT || bounds->kind == VCODE_TYPE_OFFSET,
605
      "integer register r%d has non-integer bounds", reg);
606

607
   if (bounds->low == bounds->high) {
961,799✔
608
      if (value) *value = bounds->low;
483,109✔
609
      return true;
483,109✔
610
   }
611
   else
612
      return false;
613
}
614

615
void vcode_opt(void)
54,690✔
616
{
617
   // Prune assignments to unused registers
618

619
   int *uses LOCAL = xmalloc_array(active_unit->regs.count, sizeof(int));
109,380✔
620

621
   int pruned = 0;
54,690✔
622
   do {
88,846✔
623
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
88,846✔
624
      pruned = 0;
88,846✔
625

626
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
442,242✔
627
         block_t *b = &(active_unit->blocks.items[i]);
353,396✔
628

629
         for (int j = b->ops.count - 1; j >= 0; j--) {
4,210,530✔
630
            op_t *o = &(b->ops.items[j]);
3,857,130✔
631

632
            switch (o->kind) {
3,857,130✔
633
            case VCODE_OP_FCALL:
62,746✔
634
               if (o->result == VCODE_INVALID_REG)
62,746✔
635
                  break;
636
            case VCODE_OP_CONST:
637
            case VCODE_OP_CONST_REAL:
638
            case VCODE_OP_CONST_ARRAY:
639
            case VCODE_OP_CONST_RECORD:
640
            case VCODE_OP_CONST_REP:
641
            case VCODE_OP_LOAD:
642
            case VCODE_OP_LOAD_INDIRECT:
643
            case VCODE_OP_VAR_UPREF:
644
            case VCODE_OP_ADD:
645
            case VCODE_OP_ARRAY_REF:
646
            case VCODE_OP_SUB:
647
            case VCODE_OP_MUL:
648
            case VCODE_OP_CMP:
649
            case VCODE_OP_INDEX:
650
            case VCODE_OP_WRAP:
651
            case VCODE_OP_EXP:
652
            case VCODE_OP_UNDEFINED:
653
            case VCODE_OP_UARRAY_LEN:
654
            case VCODE_OP_UARRAY_DIR:
655
            case VCODE_OP_UARRAY_LEFT:
656
            case VCODE_OP_UARRAY_RIGHT:
657
            case VCODE_OP_UNWRAP:
658
            case VCODE_OP_NULL:
659
            case VCODE_OP_ADDRESS_OF:
660
            case VCODE_OP_RANGE_NULL:
661
            case VCODE_OP_RANGE_LENGTH:
662
            case VCODE_OP_DEBUG_LOCUS:
663
            case VCODE_OP_SELECT:
664
            case VCODE_OP_CAST:
665
            case VCODE_OP_RESOLVED:
666
            case VCODE_OP_TRAP_ADD:
667
            case VCODE_OP_TRAP_SUB:
668
            case VCODE_OP_TRAP_MUL:
669
            case VCODE_OP_TRAP_EXP:
670
               if (uses[o->result] == -1) {
2,417,390✔
671
                  vcode_dump_with_mark(j, NULL, NULL);
×
672
                  fatal("defintion of r%d does not dominate all uses",
×
673
                        o->result);
674
               }
675
               else if (uses[o->result] == 0) {
2,417,390✔
676
                  if (false DEBUG_ONLY(|| o->kind != VCODE_OP_CONST)) {
321,002✔
677
                     o->comment = xasprintf("Dead %s definition of r%d",
160,213✔
678
                                            vcode_op_string(o->kind),
679
                                            o->result);
680
                     o->kind = VCODE_OP_COMMENT;
160,213✔
681
                  }
682
                  else
683
                     o->kind = (vcode_op_t)-1;
160,789✔
684
                  vcode_reg_array_resize(&(o->args), 0, VCODE_INVALID_REG);
321,002✔
685
                  pruned++;
321,002✔
686
               }
687
               uses[o->result] = -1;
2,417,390✔
688
               break;
2,417,390✔
689

690
            default:
691
               break;
692
            }
693

694
            for (int k = 0; k < o->args.count; k++) {
9,291,740✔
695
               if (o->args.items[k] != VCODE_INVALID_REG)
5,434,610✔
696
                  uses[o->args.items[k]]++;
5,395,890✔
697
            }
698
         }
699
      }
700
   } while (pruned > 0);
88,846✔
701

702
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
254,673✔
703
      block_t *b = &(active_unit->blocks.items[i]);
199,983✔
704
      op_t *dst = &(b->ops.items[0]);
199,983✔
705
      size_t copied = 0;
199,983✔
706
      for (int j = 0; j < b->ops.count; j++) {
2,287,040✔
707
         const op_t *src = &(b->ops.items[j]);
2,087,060✔
708
         if (src->kind != (vcode_op_t)-1) {
2,087,060✔
709
            if (src != dst) {
1,926,270✔
710
               assert(dst < src);
731,569✔
711
               *dst = *src;
731,569✔
712
            }
713
            dst++;
1,926,270✔
714
            copied++;
1,926,270✔
715
         }
716
      }
717

718
      assert(copied <= b->ops.count);
199,983✔
719
      b->ops.count = copied;
199,983✔
720
   }
721
}
54,690✔
722

723
void vcode_close(void)
45,382✔
724
{
725
   active_unit  = NULL;
45,382✔
726
   active_block = -1;
45,382✔
727
}
45,382✔
728

729
int vcode_count_blocks(void)
65,040✔
730
{
731
   assert(active_unit != NULL);
65,040✔
732
   return active_unit->blocks.count;
65,040✔
733
}
734

735
int vcode_count_ops(void)
217,476✔
736
{
737
   assert(active_unit != NULL);
217,476✔
738
   assert(active_block != VCODE_INVALID_BLOCK);
217,476✔
739
   return active_unit->blocks.items[active_block].ops.count;
217,476✔
740
}
741

742
int vcode_count_vars(void)
51,719✔
743
{
744
   assert(active_unit != NULL);
51,719✔
745
   return active_unit->vars.count;
51,719✔
746
}
747

748
vcode_var_t vcode_find_var(ident_t name)
13✔
749
{
750
   assert(active_unit != NULL);
13✔
751
   for (int i = 0; i < active_unit->vars.count; i++) {
22✔
752
      if (active_unit->vars.items[i].name == name)
10✔
753
         return i;
1✔
754
   }
755

756
   return VCODE_INVALID_VAR;
757
}
758

759
ident_t vcode_var_name(vcode_var_t var)
43,642✔
760
{
761
   return vcode_var_data(var)->name;
43,642✔
762
}
763

764
vcode_type_t vcode_var_type(vcode_var_t var)
143,939✔
765
{
766
   return vcode_var_data(var)->type;
143,939✔
767
}
768

769
vcode_type_t vcode_var_bounds(vcode_var_t var)
2,340✔
770
{
771
   return vcode_var_data(var)->bounds;
2,340✔
772
}
773

774
vcode_var_flags_t vcode_var_flags(vcode_var_t var)
18,008✔
775
{
776
   return vcode_var_data(var)->flags;
18,008✔
777
}
778

779
vcode_op_t vcode_get_op(int op)
2,143,570✔
780
{
781
   return vcode_op_data(op)->kind;
2,143,570✔
782
}
783

784
ident_t vcode_get_func(int op)
62,518✔
785
{
786
   op_t *o = vcode_op_data(op);
62,518✔
787
   assert(OP_HAS_FUNC(o->kind));
62,518✔
788
   return o->func;
62,518✔
789
}
790

791
ident_t vcode_get_ident(int op)
76,260✔
792
{
793
   op_t *o = vcode_op_data(op);
76,260✔
794
   assert(OP_HAS_IDENT(o->kind));
76,260✔
795
   return o->ident;
76,260✔
796
}
797

798
unsigned vcode_get_subkind(int op)
39,879✔
799
{
800
   op_t *o = vcode_op_data(op);
39,879✔
801
   assert(OP_HAS_SUBKIND(o->kind));
39,879✔
802
   return o->subkind;
39,879✔
803
}
804

805
int64_t vcode_get_value(int op)
337,565✔
806
{
807
   op_t *o = vcode_op_data(op);
337,565✔
808
   assert(OP_HAS_VALUE(o->kind));
337,565✔
809
   return o->value;
337,565✔
810
}
811

812
double vcode_get_real(int op)
10,625✔
813
{
814
   op_t *o = vcode_op_data(op);
10,625✔
815
   assert(OP_HAS_REAL(o->kind));
10,625✔
816
   return o->real;
10,625✔
817
}
818

819
vcode_var_t vcode_get_address(int op)
134,818✔
820
{
821
   op_t *o = vcode_op_data(op);
134,818✔
822
   assert(OP_HAS_ADDRESS(o->kind));
134,818✔
823
   return o->address;
134,818✔
824
}
825

826
unsigned vcode_get_dim(int op)
53,949✔
827
{
828
   op_t *o = vcode_op_data(op);
53,949✔
829
   assert(OP_HAS_DIM(o->kind));
53,949✔
830
   return o->dim;
53,949✔
831
}
832

833
int vcode_get_hops(int op)
40,957✔
834
{
835
   op_t *o = vcode_op_data(op);
40,957✔
836
   assert(OP_HAS_HOPS(o->kind));
40,957✔
837
   return o->hops;
40,957✔
838
}
839

840
int vcode_get_field(int op)
33,394✔
841
{
842
   op_t *o = vcode_op_data(op);
33,394✔
843
   assert(OP_HAS_FIELD(o->kind));
33,394✔
844
   return o->field;
33,394✔
845
}
846

847
vcode_var_t vcode_get_type(int op)
17,301✔
848
{
849
   op_t *o = vcode_op_data(op);
17,301✔
850
   assert(OP_HAS_TYPE(o->kind));
17,301✔
851
   return o->type;
17,301✔
852
}
853

854
int vcode_count_args(int op)
176,599✔
855
{
856
   return vcode_op_data(op)->args.count;
176,599✔
857
}
858

859
vcode_reg_t vcode_get_arg(int op, int arg)
3,379,960✔
860
{
861
   op_t *o = vcode_op_data(op);
3,379,960✔
862
   return vcode_reg_array_nth(&(o->args), arg);
3,379,960✔
863
}
864

865
vcode_reg_t vcode_get_result(int op)
945,694✔
866
{
867
   op_t *o = vcode_op_data(op);
945,694✔
868
   return o->result;
945,694✔
869
}
870

871
vcode_cmp_t vcode_get_cmp(int op)
27,757✔
872
{
873
   op_t *o = vcode_op_data(op);
27,757✔
874
   assert(OP_HAS_CMP(o->kind));
27,757✔
875
   return o->cmp;
27,757✔
876
}
877

878
uint32_t vcode_get_tag(int op)
1,682✔
879
{
880
   op_t *o = vcode_op_data(op);
1,682✔
881
   assert(OP_HAS_TAG(o->kind));
1,682✔
882
   return o->tag;
1,682✔
883
}
884

885
const loc_t *vcode_get_loc(int op)
1,214,170✔
886
{
887
   op_t *o = vcode_op_data(op);
1,214,170✔
888
   return &(o->loc);
1,214,170✔
889
}
890

891
vcode_block_t vcode_get_target(int op, int nth)
112,243✔
892
{
893
   op_t *o = vcode_op_data(op);
112,243✔
894
   assert(OP_HAS_TARGET(o->kind));
112,243✔
895
   return vcode_block_array_nth(&(o->targets), nth);
112,243✔
896
}
897

898
bool vcode_block_empty(void)
×
899
{
900
   assert(active_unit != NULL);
×
901
   assert(active_block != VCODE_INVALID_BLOCK);
×
902

903
   return active_unit->blocks.items[active_block].ops.count == 0;
×
904
}
905

906
bool vcode_block_finished(void)
2,194,450✔
907
{
908
   assert(active_unit != NULL);
2,194,450✔
909
   assert(active_block != VCODE_INVALID_BLOCK);
2,194,450✔
910

911
   const block_t *b = &(active_unit->blocks.items[active_block]);
2,194,450✔
912
   if (b->ops.count == 0)
2,194,450✔
913
      return false;
914
   else {
915
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,945,830✔
916
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,945,830✔
917
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,945,820✔
918
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE;
5,822,990✔
919
   }
920
}
921

922
const char *vcode_op_string(vcode_op_t op)
160,213✔
923
{
924
   static const char *strs[] = {
160,213✔
925
      "cmp", "fcall", "wait", "const", "assert", "jump", "load", "store",
926
      "mul", "add", "comment", "const array", "index", "sub", "cast",
927
      "load indirect", "store indirect", "return", "sched waveform",
928
      "cond", "report", "div", "neg", "exp", "abs", "mod", "rem", "alloc",
929
      "select", "or", "wrap", "uarray left", "uarray right", "uarray dir",
930
      "unwrap", "not", "and", "event", "active", "const record", "record ref",
931
      "copy", "sched event", "pcall", "resume", "xor", "xnor", "nand", "nor",
932
      "memset", "case", "endfile", "file open", "file write", "file close",
933
      "file read", "null", "new", "null check", "deallocate", "all",
934
      "const real", "last event", "debug out", "cover stmt", "cover branch",
935
      "cover toggle", "cover expression", "uarray len", "undefined",
936
      "range null", "var upref", "resolved", "last value", "init signal",
937
      "map signal", "drive signal", "link var", "resolution wrapper",
938
      "last active", "driving", "driving value", "address of", "closure",
939
      "protected init", "context upref", "const rep", "protected free",
940
      "implicit signal", "disconnect", "link package",
941
      "index check", "debug locus", "length check", "range check", "array ref",
942
      "range length", "exponent check", "zero check", "map const",
943
      "resolve signal", "push scope", "pop scope", "alias signal", "trap add",
944
      "trap sub", "trap mul", "force", "release", "link instance",
945
      "unreachable", "package init", "strconv", "canon value", "convstr",
946
      "trap neg", "process init", "clear event", "trap exp", "implicit event"
947
   };
948
   if ((unsigned)op >= ARRAY_LEN(strs))
160,213✔
949
      return "???";
950
   else
951
      return strs[op];
160,213✔
952
}
953

954
static int vcode_dump_reg(vcode_reg_t reg)
×
955
{
956
   int printed;
×
957
   if (reg == VCODE_INVALID_REG)
×
958
      printed = color_printf("$red$invalid$$");
×
959
   else
960
      printed = color_printf("$green$r%d$$", reg);
×
961

962
   if (dump_callback != NULL)
×
963
      printed += (*dump_callback)(VCODE_DUMP_REG, reg, dump_arg);
×
964

965
   return printed;
×
966
}
967

968
static int vcode_pretty_print_int(int64_t n)
×
969
{
970
   if (n == INT64_MAX)
×
971
      return printf("2^63-1");
×
972
   else if (n == INT64_MIN)
×
973
      return printf("-2^63");
×
974
   else if (n == INT32_MAX)
×
975
      return printf("2^31-1");
×
976
   else if (n == INT32_MIN)
×
977
      return printf("-2^31");
×
978
   else
979
      return printf("%"PRIi64, n);
×
980
}
981

982
static int vcode_dump_one_type(vcode_type_t type)
×
983
{
984
   int col = 0;
×
985
   vtype_t *vt = vcode_type_data(type);
×
986
   switch (vt->kind) {
×
987
   case VCODE_TYPE_INT:
×
988
      if (vt->low != vt->high) {
×
989
         col += vcode_pretty_print_int(vt->low);
×
990
         col += printf("..");
×
991
         col += vcode_pretty_print_int(vt->high);
×
992
      }
993
      else
994
         col += vcode_pretty_print_int(vt->low);
×
995
      break;
996

997
   case VCODE_TYPE_REAL:
×
998
      if (vt->rlow == -DBL_MAX && vt->rhigh == DBL_MAX)
×
999
         col += printf("%%");
×
1000
      else if (vt->rlow == vt->rhigh)
×
1001
         col += printf("%f", vt->rlow);
×
1002
      else
1003
         col += printf("%f..%f", vt->rlow, vt->rhigh);
×
1004
      break;
1005

1006
   case VCODE_TYPE_CARRAY:
×
1007
      {
1008
         col += printf("[%u] : ", vt->size);
×
1009
         col += vcode_dump_one_type(vt->elem);
×
1010
         if (!vtype_eq(vt->elem, vt->bounds)) {
×
1011
            col += printf(" => ");
×
1012
            col += vcode_dump_one_type(vt->bounds);
×
1013
         }
1014
      }
1015
      break;
1016

1017
   case VCODE_TYPE_UARRAY:
1018
      {
1019
         col += printf("[");
×
1020
         for (unsigned i = 0; i < vt->dims; i++)
×
1021
            col += printf("%s*", i > 0 ? ", " : "");
×
1022
         col += printf("] : ");
×
1023
         col += vcode_dump_one_type(vt->elem);
×
1024
         if (!vtype_eq(vt->elem, vt->bounds)) {
×
1025
            col += printf(" => ");
×
1026
            col += vcode_dump_one_type(vt->bounds);
×
1027
         }
1028
      }
1029
      break;
1030

1031
   case VCODE_TYPE_POINTER:
1032
      col += printf("@<");
×
1033
      col += vcode_dump_one_type(vt->pointed);
×
1034
      col += printf(">");
×
1035
      break;
×
1036

1037
   case VCODE_TYPE_ACCESS:
1038
      col += printf("A<");
×
1039
      col += vcode_dump_one_type(vt->pointed);
×
1040
      col += printf(">");
×
1041
      break;
×
1042

1043
   case VCODE_TYPE_SIGNAL:
1044
      col += printf("$<");
×
1045
      col += vcode_dump_one_type(vt->base);
×
1046
      col += printf(">");
×
1047
      break;
×
1048

1049
   case VCODE_TYPE_OFFSET:
1050
      col += printf("#");
×
1051
      break;
×
1052

1053
   case VCODE_TYPE_RECORD:
×
1054
      col += printf("%s{}", istr(vt->name));
×
1055
      break;
×
1056

1057
   case VCODE_TYPE_FILE:
1058
      col += printf("F<");
×
1059
      col += vcode_dump_one_type(vt->base);
×
1060
      col += printf(">");
×
1061
      break;
×
1062

1063
   case VCODE_TYPE_OPAQUE:
1064
      col += printf("?");
×
1065
      break;
×
1066

1067
   case VCODE_TYPE_RESOLUTION:
1068
      col += printf("R<");
×
1069
      col += vcode_dump_one_type(vt->base);
×
1070
      col += printf(">");
×
1071
      break;
×
1072

1073
   case VCODE_TYPE_CLOSURE:
1074
      col += printf("C<");
×
1075
      col += vcode_dump_one_type(vt->base);
×
1076
      col += printf(">");
×
1077
      break;
×
1078

1079
   case VCODE_TYPE_CONTEXT:
×
1080
      col += printf("P<%s>", istr(vt->name));
×
1081
      break;
×
1082

1083
   case VCODE_TYPE_DEBUG_LOCUS:
1084
      col += printf("D<>");
×
1085
      break;
×
1086
   }
1087

1088
   return col;
×
1089
}
1090

1091
static void vcode_dump_tab(int col, int to_col)
×
1092
{
1093
   if (col >= to_col)
×
1094
      printf(" ");
×
1095
   else {
1096
      while (col < to_col)
×
1097
         col += printf(" ");
×
1098
   }
1099
}
×
1100

1101
static void vcode_dump_comment(int col)
×
1102
{
1103
   vcode_dump_tab(col, 40);
×
1104
   color_printf("$cyan$// ");
×
1105
}
×
1106

1107
static void vcode_dump_type(int col, vcode_type_t type, vcode_type_t bounds)
×
1108
{
1109
   vcode_dump_comment(col);
×
1110
   vcode_dump_one_type(type);
×
1111
   if (!vtype_eq(type, bounds)) {
×
1112
      printf(" => ");
×
1113
      vcode_dump_one_type(bounds);
×
1114
   }
1115
}
×
1116

1117
static void vcode_dump_result_type(int col, const op_t *op)
1118
{
1119
   if (op->result != VCODE_INVALID_REG) {
1120
      reg_t *r = vcode_reg_data(op->result);
1121
      vcode_dump_type(col, r->type, r->bounds);
1122
   }
1123
}
1124

1125
static int vcode_dump_var(vcode_var_t var, int hops)
×
1126
{
1127
   vcode_unit_t owner = active_unit;
×
1128
   while (owner && hops--)
×
1129
      owner = owner->context;
×
1130

1131
   if (owner == NULL || var >= owner->vars.count)
×
1132
      return color_printf("$red$invalid$$");
×
1133
   else {
1134
      var_t *v = var_array_nth_ptr(&(owner->vars), var);
×
1135
      return color_printf("$magenta$%s$$", istr(v->name));
×
1136
   }
1137
}
1138

1139
LCOV_EXCL_START
1140
void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg)
1141
{
1142
   assert(active_unit != NULL);
1143

1144
   dump_callback = callback;
1145
   dump_arg = arg;
1146

1147
   const vcode_unit_t vu = active_unit;
1148
   vcode_block_t old_block = active_block;
1149

1150
   printf("\n");
1151
   if (vu->name != NULL)
1152
      color_printf("Name       $cyan$%s$$\n", istr(vu->name));
1153
   color_printf("Kind       $cyan$");
1154
   switch (vu->kind) {
1155
   case VCODE_UNIT_PROCESS:   printf("process"); break;
1156
   case VCODE_UNIT_FUNCTION:  printf("function"); break;
1157
   case VCODE_UNIT_PROCEDURE: printf("procedure"); break;
1158
   case VCODE_UNIT_INSTANCE:  printf("instance"); break;
1159
   case VCODE_UNIT_THUNK:     printf("thunk"); break;
1160
   case VCODE_UNIT_PACKAGE:   printf("package"); break;
1161
   case VCODE_UNIT_PROTECTED: printf("protected"); break;
1162
   case VCODE_UNIT_PROPERTY:  printf("property"); break;
1163
   }
1164
   color_printf("$$\n");
1165
   if (vu->context != NULL)
1166
      color_printf("Context    $cyan$%s$$\n", istr(vu->context->name));
1167
   printf("Blocks     %d\n", vu->blocks.count);
1168
   printf("Registers  %d\n", vu->regs.count);
1169
   printf("Types      %d\n", vu->types.count);
1170

1171
   for (int i = 0; i < vu->types.count; i++) {
1172
      const vtype_t *t = &(vu->types.items[i]);
1173
      if (t->kind == VCODE_TYPE_RECORD) {
1174
         int col = 0;
1175
         col += color_printf("  $magenta$%s$$", istr(t->name));
1176
         vcode_dump_tab(col, 40);
1177
         color_printf("$cyan${");
1178
         for (unsigned i = 0; i < t->fields.count; i++) {
1179
            if (i > 0)
1180
               printf(", ");
1181
            vcode_dump_one_type(t->fields.items[i]);
1182
         }
1183
         color_printf("}$$\n");
1184
      }
1185
   }
1186

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

1189
   for (int i = 0; i < vu->vars.count; i++) {
1190
      const var_t *v = &(vu->vars.items[i]);
1191
      int col = printf("  ");
1192
      col += color_printf("$magenta$%s$$", istr(v->name));
1193
      vcode_dump_type(col, v->type, v->bounds);
1194
      if (v->flags & VAR_SIGNAL)
1195
         col += printf(", signal");
1196
      if (v->flags & VAR_HEAP)
1197
         col += printf(", heap");
1198
      if (v->flags & VAR_CONST)
1199
         col += printf(", constant");
1200
      if (v->flags & VAR_TEMP)
1201
         col += printf(", temp");
1202
      color_printf("$$\n");
1203
   }
1204

1205
   if (vu->result != VCODE_INVALID_TYPE) {
1206
      color_printf("Result     $cyan$");
1207
      vcode_dump_one_type(vu->result);
1208
      color_printf("$$\n");
1209
   }
1210

1211
   if (vu->kind == VCODE_UNIT_FUNCTION
1212
       || vu->kind == VCODE_UNIT_PROCEDURE
1213
       || (vu->kind == VCODE_UNIT_THUNK && vu->params.count > 0)) {
1214

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

1217
      for (size_t i = 0; i < vu->params.count; i++) {
1218
         const param_t *p = &(vu->params.items[i]);
1219
         int col = printf("  ");
1220
         col += vcode_dump_reg(p->reg);
1221
         while (col < (dump_callback ? 12 : 8))
1222
            col += printf(" ");
1223
         col += color_printf("$magenta$%s$$", istr(p->name));
1224
         vcode_dump_type(col, p->type, p->bounds);
1225
         color_printf("$$\n");
1226
      }
1227
   }
1228

1229
   printf("Begin\n");
1230
   for (int i = 0; i < vu->blocks.count; i++) {
1231
      active_block = i;
1232
      const block_t *b = &(vu->blocks.items[i]);
1233
      for (int j = 0; j < b->ops.count; j++) {
1234
         int col = 0;
1235
         if (j == 0)
1236
            col += color_printf("  $yellow$%2d:$$ ", i);
1237
         else
1238
            col += printf("      ");
1239

1240
         const op_t *op = &(b->ops.items[j]);
1241
         switch (op->kind) {
1242
         case VCODE_OP_CMP:
1243
            {
1244
               vcode_dump_reg(op->result);
1245
               printf(" := %s ", vcode_op_string(op->kind));
1246
               vcode_dump_reg(op->args.items[0]);
1247
               switch (op->cmp) {
1248
               case VCODE_CMP_EQ:  printf(" == "); break;
1249
               case VCODE_CMP_NEQ: printf(" != "); break;
1250
               case VCODE_CMP_LT:  printf(" < "); break;
1251
               case VCODE_CMP_GT:  printf(" > "); break;
1252
               case VCODE_CMP_LEQ: printf(" <= "); break;
1253
               case VCODE_CMP_GEQ: printf(" >= "); break;
1254
               }
1255
               vcode_dump_reg(op->args.items[1]);
1256
            }
1257
            break;
1258

1259
         case VCODE_OP_CONST:
1260
            {
1261
               col += vcode_dump_reg(op->result);
1262
               col += printf(" := %s %"PRIi64"",
1263
                             vcode_op_string(op->kind),
1264
                             op->value);
1265
               vcode_dump_result_type(col, op);
1266
            }
1267
            break;
1268

1269
         case VCODE_OP_CONST_REAL:
1270
            {
1271
               col += vcode_dump_reg(op->result);
1272
               col += printf(" := %s %g",
1273
                             vcode_op_string(op->kind),
1274
                             op->real);
1275
               vcode_dump_result_type(col, op);
1276
            }
1277
            break;
1278

1279
         case VCODE_OP_ALLOC:
1280
            {
1281
               col += vcode_dump_reg(op->result);
1282
               col += printf(" := %s ", vcode_op_string(op->kind));
1283
               col += vcode_dump_reg(op->args.items[0]);
1284
               vcode_dump_result_type(col, op);
1285
            }
1286
            break;
1287

1288
         case VCODE_OP_FCALL:
1289
            {
1290
               if (op->result != VCODE_INVALID_REG) {
1291
                  col += vcode_dump_reg(op->result);
1292
                  col += printf(" := ");
1293
               }
1294
               if (op->subkind == VCODE_CC_FOREIGN)
1295
                  col += printf("foreign ");
1296
               col += color_printf("%s $magenta$%s$$ ",
1297
                                   vcode_op_string(op->kind),
1298
                                   istr(op->func));
1299
               for (int i = 0; i < op->args.count; i++) {
1300
                  if (i > 0)
1301
                     col += printf(", ");
1302
                  col += vcode_dump_reg(op->args.items[i]);
1303
               }
1304
               vcode_dump_result_type(col, op);
1305
            }
1306
            break;
1307

1308
         case VCODE_OP_MAP_CONST:
1309
            {
1310
               printf("%s ", vcode_op_string(op->kind));
1311
               vcode_dump_reg(op->args.items[0]);
1312
               printf(" to ");
1313
               vcode_dump_reg(op->args.items[1]);
1314
               printf(" count ");
1315
               vcode_dump_reg(op->args.items[2]);
1316
            }
1317
            break;
1318

1319
         case VCODE_OP_MAP_SIGNAL:
1320
            {
1321
               printf("%s ", vcode_op_string(op->kind));
1322
               vcode_dump_reg(op->args.items[0]);
1323
               printf(" to ");
1324
               vcode_dump_reg(op->args.items[1]);
1325
               if (op->args.items[2] == op->args.items[3]) {
1326
                  printf(" count ");
1327
                  vcode_dump_reg(op->args.items[2]);
1328
               }
1329
               else {
1330
                  printf(" src count ");
1331
                  vcode_dump_reg(op->args.items[2]);
1332
                  printf(" dst count ");
1333
                  vcode_dump_reg(op->args.items[3]);
1334
               }
1335
               if (op->args.count > 4) {
1336
                  printf(" conv ");
1337
                  vcode_dump_reg(op->args.items[4]);
1338
               }
1339
            }
1340
            break;
1341

1342
         case VCODE_OP_DRIVE_SIGNAL:
1343
            {
1344
               printf("%s ", vcode_op_string(op->kind));
1345
               vcode_dump_reg(op->args.items[0]);
1346
               printf(" count ");
1347
               vcode_dump_reg(op->args.items[1]);
1348
            }
1349
            break;
1350

1351
         case VCODE_OP_RESOLVE_SIGNAL:
1352
            {
1353
               printf("%s ", vcode_op_string(op->kind));
1354
               vcode_dump_reg(op->args.items[0]);
1355
               printf(" resolution ");
1356
               vcode_dump_reg(op->args.items[1]);
1357
            }
1358
            break;
1359

1360
         case VCODE_OP_PUSH_SCOPE:
1361
            {
1362
               printf("%s locus ", vcode_op_string(op->kind));
1363
               vcode_dump_reg(op->args.items[0]);
1364
            }
1365
            break;
1366

1367
         case VCODE_OP_POP_SCOPE:
1368
            {
1369
               printf("%s", vcode_op_string(op->kind));
1370
            }
1371
            break;
1372

1373
         case VCODE_OP_INIT_SIGNAL:
1374
            {
1375
               col += vcode_dump_reg(op->result);
1376
               col += printf(" := ");
1377
               col += printf("%s count ", vcode_op_string(op->kind));
1378
               col += vcode_dump_reg(op->args.items[0]);
1379
               col += printf(" size ");
1380
               col += vcode_dump_reg(op->args.items[1]);
1381
               col += printf(" value ");
1382
               col += vcode_dump_reg(op->args.items[2]);
1383
               col += printf(" flags ");
1384
               col += vcode_dump_reg(op->args.items[3]);
1385
               col += printf(" locus ");
1386
               col += vcode_dump_reg(op->args.items[4]);
1387
               if (op->args.count > 5) {
1388
                  col += printf(" offset ");
1389
                  col += vcode_dump_reg(op->args.items[5]);
1390
               }
1391
               vcode_dump_result_type(col, op);
1392
            }
1393
            break;
1394

1395
         case VCODE_OP_IMPLICIT_SIGNAL:
1396
            {
1397
               col += vcode_dump_reg(op->result);
1398
               col += printf(" := %s count ", vcode_op_string(op->kind));
1399
               col += vcode_dump_reg(op->args.items[0]);
1400
               col += printf(" size ");
1401
               col += vcode_dump_reg(op->args.items[1]);
1402
               col += printf(" locus ");
1403
               col += vcode_dump_reg(op->args.items[2]);
1404
               col += printf(" kind ");
1405
               col += vcode_dump_reg(op->args.items[3]);
1406
               col += printf(" closure ");
1407
               col += vcode_dump_reg(op->args.items[4]);
1408
            }
1409
            break;
1410

1411
         case VCODE_OP_RESOLUTION_WRAPPER:
1412
            {
1413
               col += vcode_dump_reg(op->result);
1414
               col += color_printf(" := %s ", vcode_op_string(op->kind));
1415
               col += vcode_dump_reg(op->args.items[0]);
1416
               col += printf(" ileft ");
1417
               col += vcode_dump_reg(op->args.items[1]);
1418
               col += printf(" nlits ");
1419
               col += vcode_dump_reg(op->args.items[2]);
1420
               vcode_dump_result_type(col, op);
1421
            }
1422
            break;
1423

1424
         case VCODE_OP_CLOSURE:
1425
         case VCODE_OP_PROTECTED_INIT:
1426
            {
1427
               col += vcode_dump_reg(op->result);
1428
               col += color_printf(" := %s $magenta$%s$$ context ",
1429
                                   vcode_op_string(op->kind), istr(op->func));
1430
               col += vcode_dump_reg(op->args.items[0]);
1431
               vcode_dump_result_type(col, op);
1432
            }
1433
            break;
1434

1435
         case VCODE_OP_PACKAGE_INIT:
1436
            {
1437
               col += vcode_dump_reg(op->result);
1438
               col += color_printf(" := %s $magenta$%s$$",
1439
                                   vcode_op_string(op->kind), istr(op->func));
1440
               if (op->args.count > 0) {
1441
                  col += printf(" context " );
1442
                  col += vcode_dump_reg(op->args.items[0]);
1443
               }
1444
               vcode_dump_result_type(col, op);
1445
            }
1446
            break;
1447

1448
         case VCODE_OP_PROCESS_INIT:
1449
            {
1450
               color_printf("%s $magenta$%s$$ locus ",
1451
                            vcode_op_string(op->kind), istr(op->func));
1452
               vcode_dump_reg(op->args.items[0]);
1453
            }
1454
            break;
1455

1456
         case VCODE_OP_PROTECTED_FREE:
1457
            {
1458
               printf("%s ", vcode_op_string(op->kind));
1459
               vcode_dump_reg(op->args.items[0]);
1460
            }
1461
            break;
1462

1463
         case VCODE_OP_WAIT:
1464
            {
1465
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1466
                            op->targets.items[0]);
1467
               if (op->args.items[0] != VCODE_INVALID_REG) {
1468
                  printf(" for ");
1469
                  vcode_dump_reg(op->args.items[0]);
1470
               }
1471
            }
1472
            break;
1473

1474
         case VCODE_OP_JUMP:
1475
            {
1476
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1477
                            op->targets.items[0]);
1478
            }
1479
            break;
1480

1481
         case VCODE_OP_COND:
1482
            {
1483
               printf("%s ", vcode_op_string(op->kind));
1484
               vcode_dump_reg(op->args.items[0]);
1485
               color_printf(" then $yellow$%d$$ else $yellow$%d$$",
1486
                            op->targets.items[0], op->targets.items[1]);
1487
            }
1488
            break;
1489

1490
         case VCODE_OP_ASSERT:
1491
            {
1492
               printf("%s ", vcode_op_string(op->kind));
1493
               vcode_dump_reg(op->args.items[0]);
1494
               if (op->args.items[2] != VCODE_INVALID_REG) {
1495
                  printf(" report ");
1496
                  vcode_dump_reg(op->args.items[2]);
1497
                  printf(" length ");
1498
                  vcode_dump_reg(op->args.items[3]);
1499
               }
1500
               printf(" severity ");
1501
               vcode_dump_reg(op->args.items[1]);
1502
               printf(" locus ");
1503
               vcode_dump_reg(op->args.items[4]);
1504
               if (op->args.count > 5) {
1505
                  printf(" hint ");
1506
                  vcode_dump_reg(op->args.items[5]);
1507
                  printf(" ");
1508
                  vcode_dump_reg(op->args.items[6]);
1509
               }
1510
            }
1511
            break;
1512

1513
         case VCODE_OP_REPORT:
1514
            {
1515
               printf("%s ", vcode_op_string(op->kind));
1516
               vcode_dump_reg(op->args.items[1]);
1517
               printf(" length ");
1518
               vcode_dump_reg(op->args.items[2]);
1519
               printf(" severity ");
1520
               vcode_dump_reg(op->args.items[0]);
1521
               printf(" locus ");
1522
               vcode_dump_reg(op->args.items[3]);
1523
            }
1524
            break;
1525

1526
         case VCODE_OP_LOAD:
1527
            {
1528
               col += vcode_dump_reg(op->result);
1529
               col += printf(" := %s ", vcode_op_string(op->kind));
1530
               col += vcode_dump_var(op->address, 0);
1531
               vcode_dump_result_type(col, op);
1532
            }
1533
            break;
1534

1535
         case VCODE_OP_LOAD_INDIRECT:
1536
            {
1537
               col += vcode_dump_reg(op->result);
1538
               col += color_printf(" := %s ", vcode_op_string(op->kind));
1539
               col += vcode_dump_reg(op->args.items[0]);
1540
               vcode_dump_result_type(col, op);
1541
            }
1542
            break;
1543

1544
         case VCODE_OP_STORE:
1545
            {
1546
               vcode_dump_var(op->address, 0);
1547
               printf(" := %s ", vcode_op_string(op->kind));
1548
               vcode_dump_reg(op->args.items[0]);
1549
            }
1550
            break;
1551

1552
         case VCODE_OP_STORE_INDIRECT:
1553
            {
1554
               vcode_dump_reg(op->args.items[1]);
1555
               printf(" := %s ", vcode_op_string(op->kind));
1556
               vcode_dump_reg(op->args.items[0]);
1557
            }
1558
            break;
1559

1560
         case VCODE_OP_INDEX:
1561
            {
1562
               col += vcode_dump_reg(op->result);
1563
               col += printf(" := %s ", vcode_op_string(op->kind));
1564
               col += vcode_dump_var(op->address, 0);
1565
               if (op->args.count > 0) {
1566
                  col += printf(" + ");
1567
                  col += vcode_dump_reg(op->args.items[0]);
1568
               }
1569
               vcode_dump_result_type(col, op);
1570
            }
1571
            break;
1572

1573
         case VCODE_OP_MUL:
1574
         case VCODE_OP_ADD:
1575
         case VCODE_OP_SUB:
1576
         case VCODE_OP_DIV:
1577
         case VCODE_OP_EXP:
1578
         case VCODE_OP_MOD:
1579
         case VCODE_OP_REM:
1580
         case VCODE_OP_OR:
1581
         case VCODE_OP_AND:
1582
         case VCODE_OP_XOR:
1583
         case VCODE_OP_XNOR:
1584
         case VCODE_OP_NAND:
1585
         case VCODE_OP_NOR:
1586
            {
1587
               col += vcode_dump_reg(op->result);
1588
               col += printf(" := %s ", vcode_op_string(op->kind));
1589
               col += vcode_dump_reg(op->args.items[0]);
1590
               switch (op->kind) {
1591
               case VCODE_OP_MUL:  col += printf(" * "); break;
1592
               case VCODE_OP_ADD:  col += printf(" + "); break;
1593
               case VCODE_OP_SUB:  col += printf(" - "); break;
1594
               case VCODE_OP_DIV:  col += printf(" / "); break;
1595
               case VCODE_OP_EXP:  col += printf(" ** "); break;
1596
               case VCODE_OP_MOD:  col += printf(" %% "); break;
1597
               case VCODE_OP_REM:  col += printf(" %% "); break;
1598
               case VCODE_OP_OR:   col += printf(" || "); break;
1599
               case VCODE_OP_AND:  col += printf(" && "); break;
1600
               case VCODE_OP_XOR:  col += printf(" ^ "); break;
1601
               case VCODE_OP_XNOR: col += printf(" !^ "); break;
1602
               case VCODE_OP_NAND: col += printf(" !& "); break;
1603
               case VCODE_OP_NOR:  col += printf(" !| "); break;
1604
               default: break;
1605
               }
1606
               col += vcode_dump_reg(op->args.items[1]);
1607
               vcode_dump_result_type(col, op);
1608
            }
1609
            break;
1610

1611
         case VCODE_OP_TRAP_ADD:
1612
         case VCODE_OP_TRAP_SUB:
1613
         case VCODE_OP_TRAP_MUL:
1614
         case VCODE_OP_TRAP_EXP:
1615
            {
1616
               col += vcode_dump_reg(op->result);
1617
               col += printf(" := %s ", vcode_op_string(op->kind));
1618
               col += vcode_dump_reg(op->args.items[0]);
1619
               switch (op->kind) {
1620
               case VCODE_OP_TRAP_ADD: col += printf(" + "); break;
1621
               case VCODE_OP_TRAP_SUB: col += printf(" - "); break;
1622
               case VCODE_OP_TRAP_MUL: col += printf(" * "); break;
1623
               case VCODE_OP_TRAP_EXP: col += printf(" ** "); break;
1624
               default: break;
1625
               }
1626
               col += vcode_dump_reg(op->args.items[1]);
1627
               col += printf(" locus ");
1628
               col += vcode_dump_reg(op->args.items[2]);
1629
               vcode_dump_result_type(col, op);
1630
            }
1631
            break;
1632

1633
         case VCODE_OP_NOT:
1634
         case VCODE_OP_CONVSTR:
1635
            {
1636
               col += vcode_dump_reg(op->result);
1637
               col += printf(" := %s ", vcode_op_string(op->kind));
1638
               col += vcode_dump_reg(op->args.items[0]);
1639
               vcode_dump_result_type(col, op);
1640
            }
1641
            break;
1642

1643
         case VCODE_OP_STRCONV:
1644
            {
1645
               col += vcode_dump_reg(op->result);
1646
               col += printf(" := %s ", vcode_op_string(op->kind));
1647
               col += vcode_dump_reg(op->args.items[0]);
1648
               col += printf(" length ");
1649
               col += vcode_dump_reg(op->args.items[1]);
1650
               if (op->args.count > 2) {
1651
                  col += printf(" used ");
1652
                  col += vcode_dump_reg(op->args.items[2]);
1653
               }
1654
               vcode_dump_result_type(col, op);
1655
            }
1656
            break;
1657

1658
         case VCODE_OP_CANON_VALUE:
1659
            {
1660
               col += vcode_dump_reg(op->result);
1661
               col += printf(" := %s ", vcode_op_string(op->kind));
1662
               col += vcode_dump_reg(op->args.items[0]);
1663
               col += printf(" length ");
1664
               col += vcode_dump_reg(op->args.items[1]);
1665
               vcode_dump_result_type(col, op);
1666
            }
1667
            break;
1668

1669
         case VCODE_OP_COMMENT:
1670
            {
1671
               color_printf("$cyan$// %s$$ ", op->comment);
1672
            }
1673
            break;
1674

1675
         case VCODE_OP_CONST_ARRAY:
1676
         case VCODE_OP_CONST_RECORD:
1677
            {
1678
               col += vcode_dump_reg(op->result);
1679
               col += printf(" := const %c",
1680
                             op->kind == VCODE_OP_CONST_ARRAY ? '[' : '{');
1681
               for (int k = 0; k < op->args.count; k++) {
1682
                  if (k > 0)
1683
                     col += printf(",");
1684
                  col += vcode_dump_reg(op->args.items[k]);
1685
               }
1686

1687
               putchar(op->kind == VCODE_OP_CONST_ARRAY ? ']' : '}');
1688
               vcode_dump_result_type(col + 1, op);
1689
            }
1690
            break;
1691

1692
         case VCODE_OP_CONST_REP:
1693
            {
1694
               col += vcode_dump_reg(op->result);
1695
               col += printf(" := const [");
1696
               col += vcode_dump_reg(op->args.items[0]);
1697
               col += printf("]*%"PRIi64, op->value);
1698
               vcode_dump_result_type(col, op);
1699
            }
1700
            break;
1701

1702
         case VCODE_OP_ADDRESS_OF:
1703
         case VCODE_OP_CAST:
1704
            {
1705
               col += vcode_dump_reg(op->result);
1706
               col += printf(" := %s ", vcode_op_string(op->kind));
1707
               col += vcode_dump_reg(op->args.items[0]);
1708
               vcode_dump_result_type(col, op);
1709
            }
1710
            break;
1711

1712
         case VCODE_OP_RETURN:
1713
            {
1714
               printf("%s ", vcode_op_string(op->kind));
1715
               if (op->args.count > 0)
1716
                  vcode_dump_reg(op->args.items[0]);
1717
            }
1718
            break;
1719

1720
         case VCODE_OP_SCHED_WAVEFORM:
1721
            {
1722
               printf("%s ", vcode_op_string(op->kind));
1723
               vcode_dump_reg(op->args.items[0]);
1724
               printf(" count ");
1725
               vcode_dump_reg(op->args.items[1]);
1726
               printf(" values ");
1727
               vcode_dump_reg(op->args.items[2]);
1728
               printf(" reject ");
1729
               vcode_dump_reg(op->args.items[3]);
1730
               printf(" after ");
1731
               vcode_dump_reg(op->args.items[4]);
1732
            }
1733
            break;
1734

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

1749
         case VCODE_OP_DISCONNECT:
1750
            {
1751
               printf("%s ", vcode_op_string(op->kind));
1752
               vcode_dump_reg(op->args.items[0]);
1753
               printf(" count ");
1754
               vcode_dump_reg(op->args.items[1]);
1755
               printf(" reject ");
1756
               vcode_dump_reg(op->args.items[2]);
1757
               printf(" after ");
1758
               vcode_dump_reg(op->args.items[3]);
1759
            }
1760
            break;
1761

1762
         case VCODE_OP_NEG:
1763
         case VCODE_OP_TRAP_NEG:
1764
         case VCODE_OP_ABS:
1765
         case VCODE_OP_RESOLVED:
1766
         case VCODE_OP_LAST_VALUE:
1767
            {
1768
               col += vcode_dump_reg(op->result);
1769
               col += printf(" := %s ", vcode_op_string(op->kind));
1770
               col += vcode_dump_reg(op->args.items[0]);
1771
               if (op->args.count > 1) {
1772
                  col += printf(" locus ");
1773
                  col += vcode_dump_reg(op->args.items[1]);
1774
               }
1775
               vcode_dump_result_type(col, op);
1776
            }
1777
            break;
1778

1779
         case VCODE_OP_SELECT:
1780
            {
1781
               col += vcode_dump_reg(op->result);
1782
               col += printf(" := %s ", vcode_op_string(op->kind));
1783
               col += vcode_dump_reg(op->args.items[0]);
1784
               col += printf(" then ");
1785
               col += vcode_dump_reg(op->args.items[1]);
1786
               col += printf(" else ");
1787
               col += vcode_dump_reg(op->args.items[2]);
1788
               vcode_dump_result_type(col, op);
1789
            }
1790
            break;
1791

1792
         case VCODE_OP_WRAP:
1793
            {
1794
               col += vcode_dump_reg(op->result);
1795
               col += printf(" := %s ", vcode_op_string(op->kind));
1796
               col += vcode_dump_reg(op->args.items[0]);
1797
               col += printf(" [");
1798
               for (int i = 1; i < op->args.count; i += 3) {
1799
                  if (i > 1)
1800
                     col += printf(", ");
1801
                  col += vcode_dump_reg(op->args.items[i + 0]);
1802
                  col += printf(" ");
1803
                  col += vcode_dump_reg(op->args.items[i + 1]);
1804
                  col += printf(" ");
1805
                  col += vcode_dump_reg(op->args.items[i + 2]);
1806
               }
1807
               col += printf("]");
1808
               vcode_dump_result_type(col, op);
1809
            }
1810
            break;
1811

1812
         case VCODE_OP_UARRAY_LEFT:
1813
         case VCODE_OP_UARRAY_RIGHT:
1814
         case VCODE_OP_UARRAY_DIR:
1815
         case VCODE_OP_UARRAY_LEN:
1816
            {
1817
               col += vcode_dump_reg(op->result);
1818
               col += printf(" := %s ", vcode_op_string(op->kind));
1819
               col += vcode_dump_reg(op->args.items[0]);
1820
               col += printf(" dim %d", op->dim);
1821
               vcode_dump_result_type(col, op);
1822
            }
1823
            break;
1824

1825
         case VCODE_OP_UNWRAP:
1826
            {
1827
               col += vcode_dump_reg(op->result);
1828
               col += printf(" := %s ", vcode_op_string(op->kind));
1829
               col += vcode_dump_reg(op->args.items[0]);
1830
               vcode_dump_result_type(col, op);
1831
            }
1832
            break;
1833

1834
         case VCODE_OP_VAR_UPREF:
1835
            {
1836
               col += vcode_dump_reg(op->result);
1837
               col += printf(" := %s %d, ", vcode_op_string(op->kind),
1838
                             op->hops);
1839
               col += vcode_dump_var(op->address, op->hops);
1840
               vcode_dump_result_type(col, op);
1841
            }
1842
            break;
1843

1844
         case VCODE_OP_CONTEXT_UPREF:
1845
            {
1846
               col += vcode_dump_reg(op->result);
1847
               col += printf(" := %s %d", vcode_op_string(op->kind), op->hops);
1848
               vcode_dump_result_type(col, op);
1849
            }
1850
            break;
1851

1852
         case VCODE_OP_ACTIVE:
1853
         case VCODE_OP_EVENT:
1854
         case VCODE_OP_DRIVING:
1855
            {
1856
               col += vcode_dump_reg(op->result);
1857
               col += printf(" := %s ", vcode_op_string(op->kind));
1858
               col += vcode_dump_reg(op->args.items[0]);
1859
               col += printf(" length ");
1860
               col += vcode_dump_reg(op->args.items[1]);
1861
               vcode_dump_result_type(col, op);
1862
            }
1863
            break;
1864

1865
         case VCODE_OP_RECORD_REF:
1866
            {
1867
               col += vcode_dump_reg(op->result);
1868
               col += printf(" := %s ", vcode_op_string(op->kind));
1869
               col += vcode_dump_reg(op->args.items[0]);
1870
               col += printf(" field %d", op->field);
1871
               vcode_dump_result_type(col, op);
1872
            }
1873
            break;
1874

1875
         case VCODE_OP_ARRAY_REF:
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(" offset ");
1881
               col += vcode_dump_reg(op->args.items[1]);
1882
               vcode_dump_result_type(col, op);
1883
            }
1884
            break;
1885

1886
         case VCODE_OP_COPY:
1887
            {
1888
               vcode_dump_reg(op->args.items[0]);
1889
               printf(" := %s ", vcode_op_string(op->kind));
1890
               vcode_dump_reg(op->args.items[1]);
1891
               if (op->args.count > 2) {
1892
                  printf(" count " );
1893
                  vcode_dump_reg(op->args.items[2]);
1894
               }
1895
            }
1896
            break;
1897

1898
         case VCODE_OP_SCHED_EVENT:
1899
         case VCODE_OP_CLEAR_EVENT:
1900
            {
1901
               printf("%s on ", vcode_op_string(op->kind));
1902
               vcode_dump_reg(op->args.items[0]);
1903
               printf(" count ");
1904
               vcode_dump_reg(op->args.items[1]);
1905
            }
1906
            break;
1907

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

1919
         case VCODE_OP_PCALL:
1920
            {
1921
               color_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
1922
                            istr(op->func));
1923
               for (int i = 0; i < op->args.count; i++) {
1924
                  printf("%s", i > 0 ? ", " : " ");
1925
                  vcode_dump_reg(op->args.items[i]);
1926
               }
1927
               if (op->targets.count > 0)
1928
                  color_printf(" resume $yellow$%d$$", op->targets.items[0]);
1929
            }
1930
            break;
1931

1932
         case VCODE_OP_RESUME:
1933
            {
1934
               color_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
1935
                            istr(op->func));
1936
            }
1937
            break;
1938

1939
         case VCODE_OP_MEMSET:
1940
            {
1941
               vcode_dump_reg(op->args.items[0]);
1942
               printf(" := %s ", vcode_op_string(op->kind));
1943
               vcode_dump_reg(op->args.items[1]);
1944
               printf(" length ");
1945
               vcode_dump_reg(op->args.items[2]);
1946
            }
1947
            break;
1948

1949
         case VCODE_OP_CASE:
1950
            {
1951
               printf("%s ", vcode_op_string(op->kind));
1952
               vcode_dump_reg(op->args.items[0]);
1953
               color_printf(" default $yellow$%d$$", op->targets.items[0]);
1954
               for (int i = 1; i < op->args.count; i++) {
1955
                  printf(" [");
1956
                  vcode_dump_reg(op->args.items[i]);
1957
                  color_printf(" $yellow$%d$$]", op->targets.items[i]);
1958
               }
1959
            }
1960
            break;
1961

1962
         case VCODE_OP_ENDFILE:
1963
            {
1964
               col += vcode_dump_reg(op->result);
1965
               col += printf(" := %s ", vcode_op_string(op->kind));
1966
               col += vcode_dump_reg(op->args.items[0]);
1967
               vcode_dump_result_type(col, op);
1968
            }
1969
            break;
1970

1971
         case VCODE_OP_FILE_OPEN:
1972
            {
1973
               printf("%s ", vcode_op_string(op->kind));
1974
               vcode_dump_reg(op->args.items[0]);
1975
               printf(" name ");
1976
               vcode_dump_reg(op->args.items[1]);
1977
               printf(" length ");
1978
               vcode_dump_reg(op->args.items[2]);
1979
               printf(" kind ");
1980
               vcode_dump_reg(op->args.items[3]);
1981
               if (op->args.count == 5) {
1982
                  printf(" status ");
1983
                  vcode_dump_reg(op->args.items[4]);
1984
               }
1985
            }
1986
            break;
1987

1988
         case VCODE_OP_FILE_CLOSE:
1989
            {
1990
               printf("%s ", vcode_op_string(op->kind));
1991
               vcode_dump_reg(op->args.items[0]);
1992
            }
1993
            break;
1994

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

2008
         case VCODE_OP_FILE_READ:
2009
            {
2010
               printf("%s ", vcode_op_string(op->kind));
2011
               vcode_dump_reg(op->args.items[0]);
2012
               printf(" ptr ");
2013
               vcode_dump_reg(op->args.items[1]);
2014
               if (op->args.count >= 3) {
2015
                  printf(" inlen ");
2016
                  vcode_dump_reg(op->args.items[2]);
2017
                  if (op->args.count >= 4) {
2018
                     printf(" outlen ");
2019
                     vcode_dump_reg(op->args.items[3]);
2020
                  }
2021
               }
2022
            }
2023
            break;
2024

2025
         case VCODE_OP_NULL:
2026
         case VCODE_OP_NEW:
2027
            {
2028
               col += vcode_dump_reg(op->result);
2029
               col += printf(" := %s", vcode_op_string(op->kind));
2030
               if (op->args.count == 1) {
2031
                  col += printf(" length ");
2032
                  col += vcode_dump_reg(op->args.items[0]);
2033
               }
2034
               vcode_dump_result_type(col, op);
2035
            }
2036
            break;
2037

2038
         case VCODE_OP_NULL_CHECK:
2039
            {
2040
               col += printf("%s ", vcode_op_string(op->kind));
2041
               col += vcode_dump_reg(op->args.items[0]);
2042
               col += printf(" locus ");
2043
               col += vcode_dump_reg(op->args.items[1]);
2044
            }
2045
            break;
2046

2047
         case VCODE_OP_DEALLOCATE:
2048
            {
2049
               col += printf("%s ", vcode_op_string(op->kind));
2050
               col += vcode_dump_reg(op->args.items[0]);
2051
            }
2052
            break;
2053

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

2063
         case VCODE_OP_LAST_EVENT:
2064
         case VCODE_OP_LAST_ACTIVE:
2065
         case VCODE_OP_DRIVING_VALUE:
2066
            {
2067
               col += vcode_dump_reg(op->result);
2068
               col += printf(" := %s ", vcode_op_string(op->kind));
2069
               col += vcode_dump_reg(op->args.items[0]);
2070
               if (op->args.count > 1) {
2071
                  col += printf(" length ");
2072
                  col += vcode_dump_reg(op->args.items[1]);
2073
               }
2074
               vcode_dump_result_type(col, op);
2075
            }
2076
            break;
2077

2078
         case VCODE_OP_ALIAS_SIGNAL:
2079
            {
2080
               printf("%s ", vcode_op_string(op->kind));
2081
               vcode_dump_reg(op->args.items[0]);
2082
               printf(" locus ");
2083
               vcode_dump_reg(op->args.items[1]);
2084
            }
2085
            break;
2086

2087
         case VCODE_OP_LENGTH_CHECK:
2088
            {
2089
               col += printf("%s left ", vcode_op_string(op->kind));
2090
               col += vcode_dump_reg(op->args.items[0]);
2091
               col += printf(" == right ");
2092
               col += vcode_dump_reg(op->args.items[1]);
2093
               col += printf(" locus ");
2094
               col += vcode_dump_reg(op->args.items[2]);
2095
               if (op->args.count > 3) {
2096
                  col += printf(" dim ");
2097
                  col += vcode_dump_reg(op->args.items[3]);
2098
               }
2099
            }
2100
            break;
2101

2102
         case VCODE_OP_EXPONENT_CHECK:
2103
         case VCODE_OP_ZERO_CHECK:
2104
            {
2105
               col += printf("%s ", vcode_op_string(op->kind));
2106
               col += vcode_dump_reg(op->args.items[0]);
2107
               col += printf(" locus ");
2108
               col += vcode_dump_reg(op->args.items[1]);
2109
            }
2110
            break;
2111

2112
         case VCODE_OP_INDEX_CHECK:
2113
         case VCODE_OP_RANGE_CHECK:
2114
            {
2115
               col += printf("%s ", vcode_op_string(op->kind));
2116
               col += vcode_dump_reg(op->args.items[0]);
2117
               col += printf(" left ");
2118
               col += vcode_dump_reg(op->args.items[1]);
2119
               col += printf(" right ");
2120
               col += vcode_dump_reg(op->args.items[2]);
2121
               col += printf(" dir ");
2122
               col += vcode_dump_reg(op->args.items[3]);
2123
               col += printf(" locus ");
2124
               col += vcode_dump_reg(op->args.items[4]);
2125
               if (op->args.items[5] != op->args.items[4]) {
2126
                  col += printf(" hint ");
2127
                  col += vcode_dump_reg(op->args.items[5]);
2128
               }
2129
            }
2130
            break;
2131

2132
         case VCODE_OP_DEBUG_OUT:
2133
            {
2134
               col += printf("%s ", vcode_op_string(op->kind));
2135
               col += vcode_dump_reg(op->args.items[0]);
2136
            }
2137
            break;
2138

2139
         case VCODE_OP_COVER_STMT:
2140
            {
2141
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2142
            }
2143
            break;
2144

2145
         case VCODE_OP_COVER_TOGGLE:
2146
         case VCODE_OP_COVER_BRANCH:
2147
         case VCODE_OP_COVER_EXPR:
2148
            {
2149
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2150
               vcode_dump_reg(op->args.items[0]);
2151
            }
2152
            break;
2153

2154
         case VCODE_OP_UNDEFINED:
2155
            {
2156
               col += vcode_dump_reg(op->result);
2157
               col += printf(" := %s", vcode_op_string(op->kind));
2158
               vcode_dump_result_type(col, op);
2159
            }
2160
            break;
2161

2162
         case VCODE_OP_RANGE_LENGTH:
2163
         case VCODE_OP_RANGE_NULL:
2164
            {
2165
               col += vcode_dump_reg(op->result);
2166
               col += printf(" := %s left ", vcode_op_string(op->kind));
2167
               vcode_dump_reg(op->args.items[0]);
2168
               col += printf(" right ");
2169
               vcode_dump_reg(op->args.items[1]);
2170
               col += printf(" dir ");
2171
               col += vcode_dump_reg(op->args.items[2]);
2172
               vcode_dump_result_type(col, op);
2173
            }
2174
            break;
2175

2176
         case VCODE_OP_LINK_PACKAGE:
2177
         case VCODE_OP_LINK_INSTANCE:
2178
            {
2179
               col += vcode_dump_reg(op->result);
2180
               col += color_printf(" := %s $magenta$%s$$",
2181
                                   vcode_op_string(op->kind), istr(op->ident));
2182
               if (op->args.count > 0) {
2183
                  col += printf(" locus ");
2184
                  col += vcode_dump_reg(op->args.items[0]);
2185
               }
2186
               vcode_dump_result_type(col, op);
2187
            }
2188
            break;
2189

2190
         case VCODE_OP_LINK_VAR:
2191
            {
2192
               col += vcode_dump_reg(op->result);
2193
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2194
               col += vcode_dump_reg(op->args.items[0]);
2195
               col += color_printf(" $magenta$%s$$", istr(op->ident));
2196
               vcode_dump_result_type(col, op);
2197
            }
2198
            break;
2199

2200
         case VCODE_OP_UNREACHABLE:
2201
            {
2202
               printf("%s", vcode_op_string(op->kind));
2203
               if (op->args.count > 0) {
2204
                  printf(" ");
2205
                  vcode_dump_reg(op->args.items[0]);
2206
               }
2207
            }
2208
            break;
2209

2210
         case VCODE_OP_DEBUG_LOCUS:
2211
            {
2212
               col += vcode_dump_reg(op->result);
2213
               col += color_printf(" := %s $magenta$%s$$%+"PRIi64,
2214
                                   vcode_op_string(op->kind),
2215
                                   istr(op->ident), op->value);
2216
               vcode_dump_result_type(col, op);
2217
            }
2218
            break;
2219
         }
2220

2221
         if (j == mark_op && i == old_block)
2222
            color_printf("\t $red$<----$$");
2223

2224
         color_printf("$$\n");
2225

2226
         if (callback != NULL)
2227
            (*callback)(VCODE_DUMP_OP, j, arg);
2228
      }
2229

2230
      if (b->ops.count == 0)
2231
         color_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2232
   }
2233

2234
   printf("\n");
2235
   fflush(stdout);
2236

2237
   active_block = old_block;
2238
}
2239
LCOV_EXCL_STOP
2240

2241
bool vtype_eq(vcode_type_t a, vcode_type_t b)
31,917,600✔
2242
{
2243
   assert(active_unit != NULL);
32,505,700✔
2244

2245
   if (a == b)
32,505,700✔
2246
      return true;
2247
   else {
2248
      const vtype_t *at = vcode_type_data(a);
29,791,800✔
2249
      const vtype_t *bt = vcode_type_data(b);
29,791,800✔
2250

2251
      if (at->kind != bt->kind)
29,791,800✔
2252
         return false;
2253

2254
      switch (at->kind) {
12,642,900✔
2255
      case VCODE_TYPE_INT:
11,216,800✔
2256
         return (at->low == bt->low) && (at->high == bt->high);
20,830,900✔
2257
      case VCODE_TYPE_REAL:
185,782✔
2258
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
342,493✔
2259
      case VCODE_TYPE_CARRAY:
70,076✔
2260
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
81,556✔
2261
      case VCODE_TYPE_UARRAY:
93,985✔
2262
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
117,191✔
2263
      case VCODE_TYPE_POINTER:
514,639✔
2264
      case VCODE_TYPE_ACCESS:
2265
         return vtype_eq(at->pointed, bt->pointed);
514,639✔
2266
      case VCODE_TYPE_OFFSET:
2267
      case VCODE_TYPE_OPAQUE:
2268
      case VCODE_TYPE_DEBUG_LOCUS:
2269
         return true;
2270
      case VCODE_TYPE_RESOLUTION:
73,455✔
2271
      case VCODE_TYPE_CLOSURE:
2272
      case VCODE_TYPE_SIGNAL:
2273
      case VCODE_TYPE_FILE:
2274
         return vtype_eq(at->base, bt->base);
73,455✔
2275
      case VCODE_TYPE_RECORD:
55,758✔
2276
      case VCODE_TYPE_CONTEXT:
2277
         return at->name == bt->name;
55,758✔
2278
      }
2279

2280
      return false;
×
2281
   }
2282
}
2283

2284
bool vtype_includes(vcode_type_t type, vcode_type_t bounds)
×
2285
{
2286
   const vtype_t *tt = vcode_type_data(type);
×
2287
   const vtype_t *bt = vcode_type_data(bounds);
×
2288

2289
   if (bt->kind == VCODE_TYPE_UARRAY || tt->kind == VCODE_TYPE_UARRAY)
×
2290
      return false;
2291
   else if (bt->kind != tt->kind)
×
2292
      return false;
2293

2294
   switch (bt->kind) {
×
2295
   case VCODE_TYPE_INT:
×
2296
      return bt->low >= tt->low && bt->high <= tt->high;
×
2297

2298
   case VCODE_TYPE_CARRAY:
×
2299
   case VCODE_TYPE_UARRAY:
2300
   case VCODE_TYPE_RECORD:
2301
      return vtype_eq(type, bounds);
×
2302

2303
   case VCODE_TYPE_POINTER:
2304
   case VCODE_TYPE_ACCESS:
2305
   case VCODE_TYPE_OFFSET:
2306
   case VCODE_TYPE_FILE:
2307
   case VCODE_TYPE_RESOLUTION:
2308
   case VCODE_TYPE_CLOSURE:
2309
   case VCODE_TYPE_OPAQUE:
2310
   case VCODE_TYPE_CONTEXT:
2311
   case VCODE_TYPE_DEBUG_LOCUS:
2312
      return false;
2313

2314
   case VCODE_TYPE_REAL:
×
2315
      return bt->rlow >= tt->rlow && bt->rhigh <= tt->rhigh;
×
2316

2317
   case VCODE_TYPE_SIGNAL:
×
2318
      return vtype_includes(tt->base, bt->base);
×
2319
   }
2320

2321
   return false;
2322
}
2323

2324
void vcode_dump(void)
×
2325
{
2326
   vcode_dump_with_mark(-1, NULL, NULL);
×
2327
}
×
2328

2329
static vcode_type_t vtype_new(vtype_t *new)
2330
{
2331
   int index = active_unit->types.count - 1;
2332
   vcode_type_t type = MAKE_HANDLE(active_unit->depth, index);
2333

2334
   for (int i = 0; i < index; i++) {
2335
      vcode_type_t this = MAKE_HANDLE(active_unit->depth, i);
2336
      if (vtype_eq(this, type)) {
2337
         active_unit->types.count--;
2338
         return this;
2339
      }
2340
   }
2341

2342
   return type;
2343
}
2344

2345
vcode_type_t vtype_int(int64_t low, int64_t high)
1,979,740✔
2346
{
2347
   assert(active_unit != NULL);
1,979,740✔
2348

2349
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,979,740✔
2350
   n->kind = VCODE_TYPE_INT;
1,979,740✔
2351
   n->low  = low;
1,979,740✔
2352
   n->high = high;
1,979,740✔
2353

2354
   switch (bits_for_range(low, high)) {
1,979,740✔
2355
   case 64:
89,722✔
2356
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
89,722✔
2357
      break;
89,722✔
2358
   case 32:
551,642✔
2359
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
551,642✔
2360
      break;
551,642✔
2361
   case 16:
2,631✔
2362
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
2,631✔
2363
      break;
2,631✔
2364
   case 8:
488,753✔
2365
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
488,753✔
2366
      break;
488,753✔
2367
   case 1:
846,997✔
2368
      n->repr = VCODE_REPR_U1;
846,997✔
2369
      break;
846,997✔
2370
   default:
×
2371
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
×
2372
   }
2373

2374
   return vtype_new(n);
1,979,740✔
2375
}
2376

2377
vcode_type_t vtype_bool(void)
424,901✔
2378
{
2379
   return vtype_int(0, 1);
424,901✔
2380
}
2381

2382
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
32,680✔
2383
{
2384
   assert(active_unit != NULL);
32,680✔
2385

2386
   const vtype_kind_t ekind = vtype_kind(elem);
32,680✔
2387
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
32,680✔
2388
                "array types may not be nested");
2389

2390
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
32,680✔
2391
   memset(n, '\0', sizeof(vtype_t));
32,680✔
2392
   n->kind   = VCODE_TYPE_CARRAY;
32,680✔
2393
   n->elem   = elem;
32,680✔
2394
   n->bounds = bounds;
32,680✔
2395
   n->size   = MAX(size, 0);
32,680✔
2396

2397
   return vtype_new(n);
32,680✔
2398
}
2399

2400
vcode_type_t vtype_find_named_record(ident_t name)
67,107✔
2401
{
2402
   assert(active_unit != NULL);
67,107✔
2403

2404
   for (int i = 0; i < active_unit->types.count; i++) {
522,947✔
2405
      vtype_t *other = &(active_unit->types.items[i]);
500,183✔
2406
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
500,183✔
2407
         return MAKE_HANDLE(active_unit->depth, i);
44,343✔
2408
   }
2409

2410
   return VCODE_INVALID_TYPE;
2411
}
2412

2413
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
22,764✔
2414
                                int nfields)
2415
{
2416
   assert(active_unit != NULL);
22,764✔
2417

2418
   vtype_t *data = NULL;
22,764✔
2419
   vcode_type_t handle = vtype_find_named_record(name);
22,764✔
2420
   if (handle == VCODE_INVALID_TYPE) {
22,764✔
2421
      data = vtype_array_alloc(&(active_unit->types));
11,382✔
2422
      memset(data, '\0', sizeof(vtype_t));
11,382✔
2423
      data->kind = VCODE_TYPE_RECORD;
11,382✔
2424
      data->name = name;
11,382✔
2425

2426
      handle = vtype_new(data);
11,382✔
2427
   }
2428
   else {
2429
      data = vcode_type_data(handle);
11,382✔
2430
      VCODE_ASSERT(data->fields.count == 0,
11,382✔
2431
                    "record type %s already defined", istr(name));
2432
   }
2433

2434
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
22,764✔
2435
   for (int i = 0; i < nfields; i++)
66,442✔
2436
      vcode_type_array_add(&(data->fields), field_types[i]);
43,678✔
2437

2438
   return handle;
22,764✔
2439
}
2440

2441
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
99,429✔
2442
{
2443
   assert(active_unit != NULL);
99,429✔
2444

2445
   const vtype_kind_t ekind = vtype_kind(elem);
99,429✔
2446
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
99,429✔
2447
                "array types may not be nested");
2448

2449
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
99,429✔
2450

2451
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
99,429✔
2452
   memset(n, '\0', sizeof(vtype_t));
99,429✔
2453
   n->kind   = VCODE_TYPE_UARRAY;
99,429✔
2454
   n->elem   = elem;
99,429✔
2455
   n->bounds = bounds;
99,429✔
2456
   n->dims   = ndim;
99,429✔
2457

2458
   return vtype_new(n);
99,429✔
2459
}
2460

2461
vcode_type_t vtype_pointer(vcode_type_t to)
201,302✔
2462
{
2463
   assert(active_unit != NULL);
201,302✔
2464

2465
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
201,302✔
2466
   n->kind    = VCODE_TYPE_POINTER;
201,302✔
2467
   n->pointed = to;
201,302✔
2468

2469
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
201,302✔
2470
                "cannot get pointer to carray type");
2471

2472
   return vtype_new(n);
201,302✔
2473
}
2474

2475
vcode_type_t vtype_access(vcode_type_t to)
5,386✔
2476
{
2477
   assert(active_unit != NULL);
5,386✔
2478

2479
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
5,386✔
2480
   n->kind    = VCODE_TYPE_ACCESS;
5,386✔
2481
   n->pointed = to;
5,386✔
2482

2483
   return vtype_new(n);
5,386✔
2484
}
2485

2486
vcode_type_t vtype_signal(vcode_type_t base)
29,504✔
2487
{
2488
   assert(active_unit != NULL);
29,504✔
2489

2490
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
29,504✔
2491
   n->kind = VCODE_TYPE_SIGNAL;
29,504✔
2492
   n->base = base;
29,504✔
2493

2494
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
29,504✔
2495

2496
   return vtype_new(n);
29,504✔
2497
}
2498

2499
vcode_type_t vtype_resolution(vcode_type_t base)
489✔
2500
{
2501
   assert(active_unit != NULL);
489✔
2502

2503
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
489✔
2504
   n->kind = VCODE_TYPE_RESOLUTION;
489✔
2505
   n->base = base;
489✔
2506

2507
   return vtype_new(n);
489✔
2508
}
2509

2510
vcode_type_t vtype_closure(vcode_type_t result)
606✔
2511
{
2512
   assert(active_unit != NULL);
606✔
2513

2514
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
606✔
2515
   n->kind = VCODE_TYPE_CLOSURE;
606✔
2516
   n->base = result;
606✔
2517

2518
   return vtype_new(n);
606✔
2519
}
2520

2521
vcode_type_t vtype_context(ident_t name)
56,597✔
2522
{
2523
   assert(active_unit != NULL);
56,597✔
2524

2525
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
56,597✔
2526
   n->kind = VCODE_TYPE_CONTEXT;
56,597✔
2527
   n->name = name;
56,597✔
2528

2529
   return vtype_new(n);
56,597✔
2530
}
2531

2532
vcode_type_t vtype_file(vcode_type_t base)
239✔
2533
{
2534
   assert(active_unit != NULL);
239✔
2535

2536
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
239✔
2537
   n->kind = VCODE_TYPE_FILE;
239✔
2538
   n->base = base;
239✔
2539

2540
   return vtype_new(n);
239✔
2541
}
2542

2543
vcode_type_t vtype_offset(void)
300,799✔
2544
{
2545
   assert(active_unit != NULL);
300,799✔
2546

2547
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
300,799✔
2548
   n->kind = VCODE_TYPE_OFFSET;
300,799✔
2549
   n->low  = INT32_MIN;
300,799✔
2550
   n->high = INT32_MAX;
300,799✔
2551
   n->repr = VCODE_REPR_I32;
300,799✔
2552

2553
   return vtype_new(n);
300,799✔
2554
}
2555

2556
vcode_type_t vtype_time(void)
13,450✔
2557
{
2558
   return vtype_int(INT64_MIN, INT64_MAX);
13,450✔
2559
}
2560

2561
vcode_type_t vtype_char(void)
9,563✔
2562
{
2563
   return vtype_int(0, 255);
9,563✔
2564
}
2565

2566
vcode_type_t vtype_opaque(void)
343✔
2567
{
2568
   assert(active_unit != NULL);
343✔
2569

2570
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
343✔
2571
   n->kind = VCODE_TYPE_OPAQUE;
343✔
2572

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

2576
vcode_type_t vtype_debug_locus(void)
186,374✔
2577
{
2578
   assert(active_unit != NULL);
186,374✔
2579

2580
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
186,374✔
2581
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
186,374✔
2582

2583
   return vtype_new(n);
186,374✔
2584
}
2585

2586
vcode_type_t vtype_real(double low, double high)
39,184✔
2587
{
2588
   assert(active_unit != NULL);
39,184✔
2589

2590
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
39,184✔
2591
   n->kind  = VCODE_TYPE_REAL;
39,184✔
2592
   n->rlow  = low;
39,184✔
2593
   n->rhigh = high;
39,184✔
2594

2595
   return vtype_new(n);
39,184✔
2596
}
2597

2598
vtype_kind_t vtype_kind(vcode_type_t type)
6,397,880✔
2599
{
2600
   vtype_t *vt = vcode_type_data(type);
6,397,880✔
2601
   return vt->kind;
6,397,880✔
2602
}
2603

2604
vtype_repr_t vtype_repr(vcode_type_t type)
510,798✔
2605
{
2606
   vtype_t *vt = vcode_type_data(type);
510,798✔
2607
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
510,798✔
2608
   return vt->repr;
510,798✔
2609
}
2610

2611
vcode_type_t vtype_elem(vcode_type_t type)
308,207✔
2612
{
2613
   vtype_t *vt = vcode_type_data(type);
308,207✔
2614
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
308,207✔
2615
   return vt->elem;
308,207✔
2616
}
2617

2618
vcode_type_t vtype_base(vcode_type_t type)
17,029✔
2619
{
2620
   vtype_t *vt = vcode_type_data(type);
17,029✔
2621
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
17,029✔
2622
          || vt->kind == VCODE_TYPE_RESOLUTION
2623
          || vt->kind == VCODE_TYPE_CLOSURE);
2624
   return vt->base;
17,029✔
2625
}
2626

2627
vcode_type_t vtype_bounds(vcode_type_t type)
9,639✔
2628
{
2629
   vtype_t *vt = vcode_type_data(type);
9,639✔
2630
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
9,639✔
2631
   return vt->bounds;
9,639✔
2632
}
2633

2634
unsigned vtype_dims(vcode_type_t type)
84,737✔
2635
{
2636
   vtype_t *vt = vcode_type_data(type);
84,737✔
2637
   assert(vt->kind == VCODE_TYPE_UARRAY);
84,737✔
2638
   return vt->dims;
84,737✔
2639
}
2640

2641
unsigned vtype_size(vcode_type_t type)
80,345✔
2642
{
2643
   vtype_t *vt = vcode_type_data(type);
80,345✔
2644
   assert(vt->kind == VCODE_TYPE_CARRAY);
80,345✔
2645
   return vt->size;
80,345✔
2646
}
2647

2648
int vtype_fields(vcode_type_t type)
20,648✔
2649
{
2650
   vtype_t *vt = vcode_type_data(type);
20,648✔
2651
   assert(vt->kind == VCODE_TYPE_RECORD);
20,648✔
2652
   return vt->fields.count;
20,648✔
2653
}
2654

2655
vcode_type_t vtype_field(vcode_type_t type, int field)
227,217✔
2656
{
2657
   vtype_t *vt = vcode_type_data(type);
227,217✔
2658
   assert(vt->kind == VCODE_TYPE_RECORD);
227,217✔
2659
   return vcode_type_array_nth(&(vt->fields), field);
227,217✔
2660
}
2661

2662
ident_t vtype_name(vcode_type_t type)
3,141✔
2663
{
2664
   vtype_t *vt = vcode_type_data(type);
3,141✔
2665
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
3,141✔
2666
   return vt->name;
3,141✔
2667
}
2668

2669
vcode_type_t vtype_pointed(vcode_type_t type)
364,391✔
2670
{
2671
   vtype_t *vt = vcode_type_data(type);
364,391✔
2672
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
364,391✔
2673
   return vt->pointed;
364,391✔
2674
}
2675

2676
int64_t vtype_low(vcode_type_t type)
178✔
2677
{
2678
   vtype_t *vt = vcode_type_data(type);
178✔
2679
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
178✔
2680
   return vt->low;
178✔
2681
}
2682

2683
int64_t vtype_high(vcode_type_t type)
746✔
2684
{
2685
   vtype_t *vt = vcode_type_data(type);
746✔
2686
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
746✔
2687
   return vt->high;
746✔
2688
}
2689

2690
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
439✔
2691
{
2692
   return vtype_kind(type) == VCODE_TYPE_POINTER
439✔
2693
      && vtype_kind(vtype_pointed(type)) == to;
439✔
2694
}
2695

2696
bool vtype_is_scalar(vcode_type_t type)
320,313✔
2697
{
2698
   const vtype_kind_t kind = vtype_kind(type);
320,313✔
2699
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
320,313✔
2700
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
99,933✔
2701
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
65,509✔
2702
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
62,461✔
2703
      || kind == VCODE_TYPE_CONTEXT;
320,733✔
2704
}
2705

2706
bool vtype_is_composite(vcode_type_t type)
17,510✔
2707
{
2708
   const vtype_kind_t kind = vtype_kind(type);
17,510✔
2709
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
17,510✔
2710
}
2711

2712
bool vtype_is_signal(vcode_type_t type)
192,966✔
2713
{
2714
   vtype_t *vt = vcode_type_data(type);
344,246✔
2715
   switch (vt->kind) {
344,246✔
2716
   case VCODE_TYPE_SIGNAL:
2717
      return true;
2718
   case VCODE_TYPE_POINTER:
60,070✔
2719
      return vtype_is_signal(vt->pointed);
60,070✔
2720
   case VCODE_TYPE_RECORD:
2721
      for (int i = 0; i < vt->fields.count; i++) {
47,103✔
2722
         if (vtype_is_signal(vt->fields.items[i]))
38,259✔
2723
            return true;
2724
      }
2725
      return false;
2726
   case VCODE_TYPE_UARRAY:
91,210✔
2727
   case VCODE_TYPE_CARRAY:
2728
      return vtype_is_signal(vt->elem);
91,210✔
2729
   default:
161,336✔
2730
      return false;
161,336✔
2731
   }
2732
}
2733

2734
int vtype_repr_bits(vtype_repr_t repr)
376,701✔
2735
{
2736
   switch (repr) {
376,701✔
2737
   case VCODE_REPR_U1: return 1;
2738
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2739
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2740
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2741
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2742
   default: return -1;
2743
   }
2744
}
2745

2746
bool vtype_repr_signed(vtype_repr_t repr)
42,167✔
2747
{
2748
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
42,167✔
2749
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
42,167✔
2750
}
2751

2752
static int64_t vtype_repr_low(vtype_repr_t repr)
22,144✔
2753
{
2754
   switch (repr) {
22,144✔
2755
   case VCODE_REPR_U1:
2756
   case VCODE_REPR_U8:
2757
   case VCODE_REPR_U16:
2758
   case VCODE_REPR_U32:
2759
   case VCODE_REPR_U64: return 0;
2760
   case VCODE_REPR_I8:  return INT8_MIN;
2761
   case VCODE_REPR_I16: return INT16_MIN;
2762
   case VCODE_REPR_I32: return INT32_MIN;
2763
   case VCODE_REPR_I64: return INT64_MIN;
2764
   default:             return 0;
2765
   }
2766
}
2767

2768
static uint64_t vtype_repr_high(vtype_repr_t repr)
22,144✔
2769
{
2770
   switch (repr) {
22,144✔
2771
   case VCODE_REPR_U1:  return 1;
2772
   case VCODE_REPR_U8:  return UINT8_MAX;
2773
   case VCODE_REPR_U16: return UINT16_MAX;
2774
   case VCODE_REPR_U32: return UINT32_MAX;
2775
   case VCODE_REPR_U64: return UINT64_MAX;
2776
   case VCODE_REPR_I8:  return INT8_MAX;
2777
   case VCODE_REPR_I16: return INT16_MAX;
2778
   case VCODE_REPR_I32: return INT32_MAX;
2779
   case VCODE_REPR_I64: return INT64_MAX;
2780
   default:             return 0;
2781
   }
2782
}
2783

2784
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
22,144✔
2785
{
2786
   int64_t clamp_low = vtype_repr_low(repr);
22,144✔
2787
   uint64_t clamp_high = vtype_repr_high(repr);
22,144✔
2788

2789
   if (*low >= clamp_low && *high <= clamp_high)
22,144✔
2790
      return true;
2791
   else {
2792
      *low = MAX(clamp_low, *low);
18,252✔
2793
      *high = MIN(clamp_high, *high);
18,252✔
2794
      return false;
18,252✔
2795
   }
2796
}
2797

2798
int vcode_count_params(void)
23,132✔
2799
{
2800
   assert(active_unit != NULL);
23,132✔
2801
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
23,132✔
2802
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2803
          || active_unit->kind == VCODE_UNIT_THUNK);
2804

2805
   return active_unit->params.count;
23,132✔
2806
}
2807

2808
vcode_type_t vcode_param_type(int param)
24,801✔
2809
{
2810
   assert(active_unit != NULL);
24,801✔
2811
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
24,801✔
2812
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2813
          || active_unit->kind == VCODE_UNIT_THUNK);
2814
   assert(param < active_unit->params.count);
24,801✔
2815

2816
   return active_unit->params.items[param].type;
24,801✔
2817
}
2818

2819
vcode_reg_t vcode_param_reg(int param)
31,450✔
2820
{
2821
   assert(active_unit != NULL);
31,450✔
2822
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,450✔
2823
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2824
          || active_unit->kind == VCODE_UNIT_THUNK);
2825
   assert(param < active_unit->params.count);
31,450✔
2826

2827
   return active_unit->params.items[param].reg;
31,450✔
2828
}
2829

2830
vcode_block_t emit_block(void)
199,983✔
2831
{
2832
   assert(active_unit != NULL);
199,983✔
2833

2834
   vcode_block_t bnum = active_unit->blocks.count;
199,983✔
2835

2836
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
199,983✔
2837
   memset(bptr, '\0', sizeof(block_t));
199,983✔
2838

2839
   if (active_block != VCODE_INVALID_BLOCK)
199,983✔
2840
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
145,293✔
2841
   else
2842
      bptr->last_loc = LOC_INVALID;
54,690✔
2843

2844
   return bnum;
199,983✔
2845
}
2846

2847
void vcode_select_unit(vcode_unit_t unit)
415,824✔
2848
{
2849
   active_unit  = unit;
415,824✔
2850
   active_block = VCODE_INVALID_BLOCK;
415,824✔
2851
}
415,824✔
2852

2853
void vcode_select_block(vcode_block_t block)
464,391✔
2854
{
2855
   assert(active_unit != NULL);
464,391✔
2856
   active_block = block;
464,391✔
2857
}
464,391✔
2858

2859
vcode_block_t vcode_active_block(void)
1,277,940✔
2860
{
2861
   assert(active_unit != NULL);
1,277,940✔
2862
   assert(active_block != -1);
1,277,940✔
2863
   return active_block;
1,277,940✔
2864
}
2865

2866
const loc_t *vcode_last_loc(void)
832,576✔
2867
{
2868
   return &(vcode_block_data()->last_loc);
832,576✔
2869
}
2870

2871
vcode_unit_t vcode_active_unit(void)
67,707✔
2872
{
2873
   assert(active_unit != NULL);
67,707✔
2874
   return active_unit;
67,707✔
2875
}
2876

2877
ident_t vcode_unit_name(void)
222,635✔
2878
{
2879
   assert(active_unit != NULL);
222,635✔
2880
   return active_unit->name;
222,635✔
2881
}
2882

2883
bool vcode_unit_has_undefined(void)
16,752✔
2884
{
2885
   assert(active_unit != NULL);
16,752✔
2886
   return !!(active_unit->flags & UNIT_UNDEFINED);
16,752✔
2887
}
2888

2889
bool vcode_unit_has_escaping_tlab(vcode_unit_t vu)
3,762✔
2890
{
2891
   return !!(vu->flags & UNIT_ESCAPING_TLAB);
3,762✔
2892
}
2893

2894
int vcode_unit_depth(void)
×
2895
{
2896
   assert(active_unit != NULL);
×
2897
   return active_unit->depth;
×
2898
}
2899

2900
void vcode_set_result(vcode_type_t type)
39,293✔
2901
{
2902
   assert(active_unit != NULL);
39,293✔
2903
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
39,293✔
2904
          || active_unit->kind == VCODE_UNIT_THUNK);
2905

2906
   active_unit->result = type;
39,293✔
2907
}
39,293✔
2908

2909
vcode_type_t vcode_unit_result(void)
58,517✔
2910
{
2911
   assert(active_unit != NULL);
58,517✔
2912
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
58,517✔
2913
          || active_unit->kind == VCODE_UNIT_THUNK);
2914
   return active_unit->result;
58,517✔
2915
}
2916

2917
vunit_kind_t vcode_unit_kind(void)
366,389✔
2918
{
2919
   assert(active_unit != NULL);
366,389✔
2920
   return active_unit->kind;
366,389✔
2921
}
2922

2923
vcode_unit_t vcode_unit_context(void)
121,392✔
2924
{
2925
   assert(active_unit != NULL);
121,392✔
2926
   return active_unit->context;
121,392✔
2927
}
2928

2929
object_t *vcode_unit_object(vcode_unit_t vu)
59,372✔
2930
{
2931
   assert(vu != NULL);
59,372✔
2932
   return object_from_locus(vu->module, vu->offset,
59,372✔
2933
                            (object_load_fn_t)lib_get_qualified);
2934
}
2935

2936
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
69,763✔
2937
{
2938
   int hops = 0;
69,763✔
2939
   for (; (unit = unit->context); hops++)
130,783✔
2940
      ;
61,020✔
2941
   return hops;
69,763✔
2942
}
2943

2944
static void vcode_registry_add(vcode_unit_t vu)
361,990✔
2945
{
2946
   if (registry == NULL)
361,990✔
2947
      registry = hash_new(512);
3,215✔
2948

2949
   hash_put(registry, vu->name, vu);
361,990✔
2950
}
361,990✔
2951

2952
vcode_unit_t vcode_find_unit(ident_t name)
431,635✔
2953
{
2954
   if (registry == NULL)
431,635✔
2955
      return NULL;
2956
   else
2957
      return hash_get(registry, name);
431,635✔
2958
}
2959

2960
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
2961
{
2962
   if (context->kind == VCODE_UNIT_THUNK && child->kind != VCODE_UNIT_THUNK)
2963
      fatal_trace("thunk may not have non-thunk children");
2964

2965
   child->next = NULL;
2966
   if (context->children == NULL)
2967
      context->children = child;
2968
   else {
2969
      vcode_unit_t it;
2970
      for (it = context->children; it->next != NULL; it = it->next)
2971
         ;
2972
      it->next = child;
2973
   }
2974
}
2975

2976
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
25,658✔
2977
{
2978
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
25,658✔
2979
   vu->kind     = VCODE_UNIT_FUNCTION;
25,658✔
2980
   vu->name     = name;
25,658✔
2981
   vu->context  = context;
25,658✔
2982
   vu->result   = VCODE_INVALID_TYPE;
25,658✔
2983
   vu->depth    = vcode_unit_calc_depth(vu);
25,658✔
2984

2985
   object_locus(obj, &vu->module, &vu->offset);
25,658✔
2986

2987
   vcode_add_child(context, vu);
25,658✔
2988

2989
   vcode_select_unit(vu);
25,658✔
2990
   vcode_select_block(emit_block());
25,658✔
2991
   emit_debug_info(&(obj->loc));
25,658✔
2992

2993
   vcode_registry_add(vu);
25,658✔
2994

2995
   return vu;
25,658✔
2996
}
2997

2998
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
702✔
2999
{
3000
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
702✔
3001
   vu->kind     = VCODE_UNIT_PROCEDURE;
702✔
3002
   vu->name     = name;
702✔
3003
   vu->context  = context;
702✔
3004
   vu->result   = VCODE_INVALID_TYPE;
702✔
3005
   vu->depth    = vcode_unit_calc_depth(vu);
702✔
3006

3007
   object_locus(obj, &vu->module, &vu->offset);
702✔
3008

3009
   vcode_add_child(context, vu);
702✔
3010

3011
   vcode_select_unit(vu);
702✔
3012
   vcode_select_block(emit_block());
702✔
3013
   emit_debug_info(&(obj->loc));
702✔
3014

3015
   vcode_registry_add(vu);
702✔
3016

3017
   return vu;
702✔
3018
}
3019

3020
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
6,346✔
3021
{
3022
   assert(context->kind == VCODE_UNIT_INSTANCE);
6,346✔
3023

3024
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
6,346✔
3025
   vu->kind     = VCODE_UNIT_PROCESS;
6,346✔
3026
   vu->name     = name;
6,346✔
3027
   vu->context  = context;
6,346✔
3028
   vu->depth    = vcode_unit_calc_depth(vu);
6,346✔
3029
   vu->result   = VCODE_INVALID_TYPE;
6,346✔
3030

3031
   object_locus(obj, &vu->module, &vu->offset);
6,346✔
3032

3033
   vcode_add_child(context, vu);
6,346✔
3034

3035
   vcode_select_unit(vu);
6,346✔
3036
   vcode_select_block(emit_block());
6,346✔
3037
   emit_debug_info(&(obj->loc));
6,346✔
3038

3039
   vcode_registry_add(vu);
6,346✔
3040

3041
   return vu;
6,346✔
3042
}
3043

3044
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
6,027✔
3045
{
3046
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
6,027✔
3047

3048
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
6,027✔
3049
   vu->kind     = VCODE_UNIT_INSTANCE;
6,027✔
3050
   vu->name     = name;
6,027✔
3051
   vu->context  = context;
6,027✔
3052
   vu->depth    = vcode_unit_calc_depth(vu);
6,027✔
3053
   vu->result   = VCODE_INVALID_TYPE;
6,027✔
3054

3055
   object_locus(obj, &vu->module, &vu->offset);
6,027✔
3056

3057
   if (context != NULL)
6,027✔
3058
      vcode_add_child(context, vu);
3,554✔
3059

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

3064
   vcode_registry_add(vu);
6,027✔
3065

3066
   return vu;
6,027✔
3067
}
3068

3069
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
797✔
3070
{
3071
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
797✔
3072
   vu->kind     = VCODE_UNIT_PACKAGE;
797✔
3073
   vu->name     = name;
797✔
3074
   vu->context  = context;
797✔
3075
   vu->depth    = vcode_unit_calc_depth(vu);
797✔
3076
   vu->result   = VCODE_INVALID_TYPE;
797✔
3077

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

3080
   if (context != NULL)
797✔
3081
      vcode_add_child(context, vu);
92✔
3082

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

3087
   vcode_registry_add(vu);
797✔
3088

3089
   return vu;
797✔
3090
}
3091

3092
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
81✔
3093
{
3094
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
81✔
3095
   vu->kind     = VCODE_UNIT_PROTECTED;
81✔
3096
   vu->name     = name;
81✔
3097
   vu->context  = context;
81✔
3098
   vu->depth    = vcode_unit_calc_depth(vu);
81✔
3099
   vu->result   = VCODE_INVALID_TYPE;
81✔
3100

3101
   object_locus(obj, &vu->module, &vu->offset);
81✔
3102

3103
   if (context != NULL)
81✔
3104
      vcode_add_child(context, vu);
81✔
3105

3106
   vcode_select_unit(vu);
81✔
3107
   vcode_select_block(emit_block());
81✔
3108
   emit_debug_info(&(obj->loc));
81✔
3109

3110
   vcode_registry_add(vu);
81✔
3111

3112
   return vu;
81✔
3113
}
3114

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

3124
   object_locus(obj, &vu->module, &vu->offset);
6✔
3125

3126
   if (context != NULL)
6✔
3127
      vcode_add_child(context, vu);
6✔
3128

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

3133
   vcode_registry_add(vu);
6✔
3134

3135
   return vu;
6✔
3136
}
3137

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

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

3150
   if (context != NULL)
15,073✔
3151
      vcode_add_child(context, vu);
105✔
3152

3153
   vcode_select_unit(vu);
15,073✔
3154
   vcode_select_block(emit_block());
15,073✔
3155

3156
   if (name != NULL)
15,073✔
3157
      vcode_registry_add(vu);
×
3158

3159
   return vu;
15,073✔
3160
}
3161

3162
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
9,969✔
3163
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3164
                 vcode_reg_t hint_right)
3165
{
3166
   int64_t value_const;
9,969✔
3167
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
9,969✔
3168
      emit_comment("Always true assertion on r%d", value);
×
3169
      return;
×
3170
   }
3171

3172
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
9,969✔
3173
   vcode_add_arg(op, value);
9,969✔
3174
   vcode_add_arg(op, severity);
9,969✔
3175
   vcode_add_arg(op, message);
9,969✔
3176
   vcode_add_arg(op, length);
9,969✔
3177
   vcode_add_arg(op, locus);
9,969✔
3178

3179
   if (hint_left != VCODE_INVALID_REG) {
9,969✔
3180
      vcode_add_arg(op, hint_left);
4,041✔
3181
      vcode_add_arg(op, hint_right);
4,041✔
3182

3183
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
4,041✔
3184
                   "left hint must be scalar");
3185
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
4,041✔
3186
                   "right hint must be scalar");
3187
   }
3188

3189
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
9,969✔
3190
                "value parameter to assert is not bool");
3191
   VCODE_ASSERT(message == VCODE_INVALID_REG
9,969✔
3192
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3193
                "message parameter to assert is not a pointer");
3194
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
9,969✔
3195
                "value parameter to assert is not bool");
3196
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
9,969✔
3197
                "locus argument to report must be a debug locus");
3198
}
3199

3200
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,919✔
3201
                 vcode_reg_t locus)
3202
{
3203
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,919✔
3204
   vcode_add_arg(op, severity);
2,919✔
3205
   vcode_add_arg(op, message);
2,919✔
3206
   vcode_add_arg(op, length);
2,919✔
3207
   vcode_add_arg(op, locus);
2,919✔
3208

3209
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,919✔
3210
                "message parameter to report is not a pointer");
3211
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,919✔
3212
                "message parameter to report is not a character pointer");
3213
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,919✔
3214
                "locus argument to report must be a debug locus");
3215
}
2,919✔
3216

3217
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
91,930✔
3218
{
3219
   if (lhs == rhs) {
91,930✔
3220
      if (cmp == VCODE_CMP_EQ)
8,554✔
3221
         return emit_const(vtype_bool(), 1);
8,307✔
3222
      else if (cmp == VCODE_CMP_NEQ)
247✔
3223
         return emit_const(vtype_bool(), 0);
2✔
3224
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
245✔
3225
         return emit_const(vtype_bool(), 1);
×
3226
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
245✔
3227
         return emit_const(vtype_bool(), 0);
245✔
3228
   }
3229

3230
   int64_t lconst, rconst;
83,376✔
3231
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
83,376✔
3232
      switch (cmp) {
1,153✔
3233
      case VCODE_CMP_EQ:
939✔
3234
         return emit_const(vtype_bool(), lconst == rconst);
939✔
3235
      case VCODE_CMP_NEQ:
40✔
3236
         return emit_const(vtype_bool(), lconst != rconst);
40✔
3237
      case VCODE_CMP_LT:
11✔
3238
         return emit_const(vtype_bool(), lconst < rconst);
11✔
3239
      case VCODE_CMP_GT:
158✔
3240
         return emit_const(vtype_bool(), lconst > rconst);
158✔
3241
      case VCODE_CMP_LEQ:
2✔
3242
         return emit_const(vtype_bool(), lconst <= rconst);
2✔
3243
      case VCODE_CMP_GEQ:
3✔
3244
         return emit_const(vtype_bool(), lconst >= rconst);
3✔
3245
      default:
×
3246
         fatal_trace("cannot fold comparison %d", cmp);
×
3247
      }
3248
   }
3249

3250
   // Reuse any previous operation in this block with the same arguments
3251
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
844,639✔
3252
      if (other->args.count == 2 && other->args.items[0] == lhs
29,469✔
3253
          && other->args.items[1] == rhs && other->cmp == cmp)
4,390✔
3254
         return other->result;
347✔
3255
   }
3256

3257
   op_t *op = vcode_add_op(VCODE_OP_CMP);
81,876✔
3258
   vcode_add_arg(op, lhs);
81,876✔
3259
   vcode_add_arg(op, rhs);
81,876✔
3260
   op->cmp    = cmp;
81,876✔
3261
   op->result = vcode_add_reg(vtype_bool());
81,876✔
3262

3263
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
81,876✔
3264
                "arguments to cmp are not the same type");
3265

3266
   return op->result;
3267
}
3268

3269
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_type_t bounds,
35,804✔
3270
                       vcode_cc_t cc, const vcode_reg_t *args, int nargs)
3271
{
3272
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
35,804✔
3273
   o->func    = func;
35,804✔
3274
   o->type    = type;
35,804✔
3275
   o->subkind = cc;
35,804✔
3276
   for (int i = 0; i < nargs; i++)
141,559✔
3277
      vcode_add_arg(o, args[i]);
105,755✔
3278

3279
   for (int i = 0; i < nargs; i++)
141,559✔
3280
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
105,755✔
3281
                   "invalid argument to function");
3282

3283
   if (cc != VCODE_CC_FOREIGN)
35,804✔
3284
      VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
34,696✔
3285
                   "first argument to VHDL function must be context pointer");
3286

3287
   if (type == VCODE_INVALID_TYPE)
35,804✔
3288
      return (o->result = VCODE_INVALID_REG);
2,112✔
3289
   else {
3290
      o->result = vcode_add_reg(type);
33,692✔
3291

3292
      reg_t *rr = vcode_reg_data(o->result);
33,692✔
3293
      rr->bounds = bounds;
33,692✔
3294

3295
      return o->result;
33,692✔
3296
   }
3297
}
3298

3299
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
2,266✔
3300
                vcode_block_t resume_bb)
3301
{
3302
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
2,266✔
3303
   o->func    = func;
2,266✔
3304
   o->subkind = VCODE_CC_VHDL;
2,266✔
3305
   for (int i = 0; i < nargs; i++)
11,497✔
3306
      vcode_add_arg(o, args[i]);
9,231✔
3307

3308
   vcode_block_array_add(&(o->targets), resume_bb);
2,266✔
3309

3310
   for (int i = 0; i < nargs; i++)
11,497✔
3311
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
9,231✔
3312
                   "invalid argument to procedure");
3313

3314
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
2,266✔
3315
                "first argument to VHDL procedure must be context pointer");
3316
}
2,266✔
3317

3318
vcode_reg_t emit_alloc(vcode_type_t type, vcode_type_t bounds,
9,551✔
3319
                       vcode_reg_t count)
3320
{
3321
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
9,551✔
3322
   op->type    = type;
9,551✔
3323
   op->result  = vcode_add_reg(vtype_pointer(type));
9,551✔
3324
   vcode_add_arg(op, count);
9,551✔
3325

3326
   const vtype_kind_t tkind = vtype_kind(type);
9,551✔
3327
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
9,551✔
3328
                "alloca element type cannot be array");
3329
   VCODE_ASSERT(count != VCODE_INVALID_REG,
9,551✔
3330
                "alloca must have valid count argument");
3331

3332
   reg_t *r = vcode_reg_data(op->result);
9,551✔
3333
   r->bounds = bounds;
9,551✔
3334

3335
   return op->result;
9,551✔
3336
}
3337

3338
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
1,126,190✔
3339
{
3340
   // Reuse any previous constant in this block with the same type and value
3341
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
28,224,500✔
3342
      if (other->kind == VCODE_OP_CONST && other->value == value
7,720,150✔
3343
          && vtype_eq(type, other->type))
901,484✔
3344
         return other->result;
607,282✔
3345
   }
3346

3347
   op_t *op = vcode_add_op(VCODE_OP_CONST);
518,905✔
3348
   op->value  = value;
518,905✔
3349
   op->type   = type;
518,905✔
3350
   op->result = vcode_add_reg(type);
518,905✔
3351

3352
   vtype_kind_t type_kind = vtype_kind(type);
518,905✔
3353
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
518,905✔
3354
                "constant must have integer or offset type");
3355

3356
   reg_t *r = vcode_reg_data(op->result);
518,905✔
3357
   r->bounds = vtype_int(value, value);
518,905✔
3358

3359
   return op->result;
518,905✔
3360
}
3361

3362
vcode_reg_t emit_const_real(vcode_type_t type, double value)
13,840✔
3363
{
3364
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
374,256✔
3365
      if (other->real == value && other->type == type)
145,736✔
3366
         return other->result;
4,064✔
3367
   }
3368

3369
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
9,776✔
3370
   op->real   = value;
9,776✔
3371
   op->type   = type;
9,776✔
3372
   op->result = vcode_add_reg(op->type);
9,776✔
3373

3374
   reg_t *r = vcode_reg_data(op->result);
9,776✔
3375
   r->bounds = vtype_real(value, value);
9,776✔
3376

3377
   return op->result;
9,776✔
3378
}
3379

3380
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
18,022✔
3381
{
3382
   vtype_kind_t kind = vtype_kind(type);
18,022✔
3383

3384
   // Reuse any previous operation in this block with the same arguments
3385
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
589,245✔
3386
      if (other->args.count != num)
25,129✔
3387
         continue;
14,324✔
3388
      else if (!vtype_eq(vcode_reg_type(other->result), type))
10,805✔
3389
         continue;
381✔
3390

3391
      bool match = true;
3392
      for (int i = 0; match && i < num; i++) {
200,519✔
3393
         if (other->args.items[i] != values[i])
190,095✔
3394
            match = false;
9,058✔
3395
      }
3396

3397
      if (match) return other->result;
10,424✔
3398
   }
3399

3400
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
16,656✔
3401
   op->result = vcode_add_reg(type);
16,656✔
3402

3403
   for (int i = 0; i < num; i++)
1,141,980✔
3404
      vcode_add_arg(op, values[i]);
1,125,330✔
3405

3406
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
16,656✔
3407
                "constant array must have constrained array type");
3408
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
16,656✔
3409
                vtype_size(type), num);
3410

3411
#ifndef NDEBUG
3412
   vcode_type_t elem = vtype_elem(type);
16,656✔
3413
   for (int i = 0; i < num; i++)
1,141,980✔
3414
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,125,330✔
3415
                   "wrong element type for item %d", i);
3416
#endif
3417

3418
   reg_t *r = vcode_reg_data(op->result);
16,656✔
3419
   r->bounds = vtype_elem(type);
16,656✔
3420

3421
   return op->result;
16,656✔
3422
}
3423

3424
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
107✔
3425
{
3426
   // Reuse any previous operation in this block with the same arguments
3427
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
3,344✔
3428
      if (other->args.items[0] == value && other->value == rep)
141✔
3429
         return other->result;
45✔
3430
   }
3431

3432
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
62✔
3433
   op->value = rep;
62✔
3434
   vcode_add_arg(op, value);
62✔
3435

3436
   VCODE_ASSERT(vcode_reg_const(value, NULL)
62✔
3437
                || vcode_reg_kind(value) == VCODE_TYPE_REAL,
3438
                "constant array must have constant values");
3439
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
62✔
3440
                "constant array must have constrained array type");
3441

3442
   op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
62✔
3443

3444
   reg_t *r = vcode_reg_data(op->result);
62✔
3445
   r->bounds = vtype_bounds(type);
62✔
3446

3447
   return op->result;
62✔
3448
}
3449

3450
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
2,170✔
3451
{
3452
   // Reuse any previous constant in this block with the same type and value
3453
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
38,854✔
3454
      if (vtype_eq(type, other->type) && other->args.count == num) {
1,518✔
3455
         bool same_regs = true;
3456
         for (int i = 0; i < num; i++)
3,837✔
3457
            same_regs = same_regs && other->args.items[i] == values[i];
4,169✔
3458

3459
         if (same_regs && vtype_eq(vcode_reg_type(other->result), type))
920✔
3460
            return other->result;
387✔
3461
      }
3462
   }
3463

3464
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
1,783✔
3465
   op->type   = type;
1,783✔
3466
   op->result = vcode_add_reg(type);
1,783✔
3467

3468
   for (int i = 0; i < num; i++)
7,436✔
3469
      vcode_add_arg(op, values[i]);
5,653✔
3470

3471
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
1,783✔
3472
                "constant record must have record type");
3473

3474
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
1,783✔
3475
                vtype_fields(type), num);
3476

3477
   for (int i = 0; i < num; i++) {
7,436✔
3478
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
5,653✔
3479
                   "wrong type for field %d", i);
3480

3481
      op_t *defn = vcode_find_definition(values[i]);
5,653✔
3482
      VCODE_ASSERT(defn != NULL, "constant record uses parameter r%d",
5,653✔
3483
                   values[i]);
3484
      VCODE_ASSERT(defn->kind == VCODE_OP_CONST
5,653✔
3485
                   || defn->kind == VCODE_OP_CONST_REAL
3486
                   || defn->kind == VCODE_OP_CONST_RECORD
3487
                   || defn->kind == VCODE_OP_CONST_ARRAY
3488
                   || defn->kind == VCODE_OP_NULL
3489
                   || defn->kind == VCODE_OP_UNDEFINED,
3490
                   "constant record field r%d is not constant", values[i]);
3491
   }
3492

3493
   return op->result;
1,783✔
3494
}
3495

3496
vcode_reg_t emit_address_of(vcode_reg_t value)
18,829✔
3497
{
3498
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
635,038✔
3499
      if (other->args.items[0] == value)
25,574✔
3500
         return other->result;
1,319✔
3501
   }
3502

3503
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
17,510✔
3504
   vcode_add_arg(op, value);
17,510✔
3505

3506
   vcode_type_t type = vcode_reg_type(value);
17,510✔
3507
   VCODE_ASSERT(vtype_is_composite(type),
17,510✔
3508
                "address of argument must be record or array");
3509

3510
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
17,510✔
3511
      vcode_type_t elem = vtype_elem(type);
16,181✔
3512
      op->result = vcode_add_reg(vtype_pointer(elem));
16,181✔
3513

3514
      reg_t *rr = vcode_reg_data(op->result);
16,181✔
3515
      rr->bounds = elem;
16,181✔
3516

3517
      return op->result;
16,181✔
3518
   }
3519
   else
3520
      return (op->result = vcode_add_reg(vtype_pointer(type)));
1,329✔
3521
}
3522

3523
void emit_wait(vcode_block_t target, vcode_reg_t time)
10,186✔
3524
{
3525
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
10,186✔
3526
   vcode_add_target(op, target);
10,186✔
3527
   vcode_add_arg(op, time);
10,186✔
3528

3529
   VCODE_ASSERT(time == VCODE_INVALID_REG
10,186✔
3530
                || vcode_reg_kind(time) == VCODE_TYPE_INT,
3531
                "wait time must have integer type");
3532
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
10,186✔
3533
                || active_unit->kind == VCODE_UNIT_PROCESS,
3534
                "wait only allowed in process or procedure");
3535
}
10,186✔
3536

3537
void emit_jump(vcode_block_t target)
49,465✔
3538
{
3539
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
49,465✔
3540
   vcode_add_target(op, target);
49,465✔
3541
}
49,465✔
3542

3543
vcode_var_t emit_var(vcode_type_t type, vcode_type_t bounds, ident_t name,
52,863✔
3544
                     vcode_var_flags_t flags)
3545
{
3546
   assert(active_unit != NULL);
52,863✔
3547

3548
   vcode_var_t var = active_unit->vars.count;
52,863✔
3549
   var_t *v = var_array_alloc(&(active_unit->vars));
52,863✔
3550
   memset(v, '\0', sizeof(var_t));
52,863✔
3551
   v->type     = type;
52,863✔
3552
   v->bounds   = bounds;
52,863✔
3553
   v->name     = name;
52,863✔
3554
   v->flags    = flags;
52,863✔
3555

3556
   return var;
52,863✔
3557
}
3558

3559
vcode_reg_t emit_param(vcode_type_t type, vcode_type_t bounds, ident_t name)
76,726✔
3560
{
3561
   assert(active_unit != NULL);
76,726✔
3562

3563
   param_t *p = param_array_alloc(&(active_unit->params));
76,726✔
3564
   memset(p, '\0', sizeof(param_t));
76,726✔
3565
   p->type   = type;
76,726✔
3566
   p->bounds = bounds;
76,726✔
3567
   p->name   = name;
76,726✔
3568
   p->reg    = vcode_add_reg(type);
76,726✔
3569

3570
   reg_t *rr = vcode_reg_data(p->reg);
76,726✔
3571
   rr->bounds = bounds;
76,726✔
3572

3573
   return p->reg;
76,726✔
3574
}
3575

3576
vcode_reg_t emit_load(vcode_var_t var)
89,374✔
3577
{
3578
   // Try scanning backwards through the block for another load or store to
3579
   // this variable
3580
   vcode_reg_t fold = VCODE_INVALID_REG;
89,374✔
3581
   bool aliased = false;
89,374✔
3582
   VCODE_FOR_EACH_OP(other) {
1,033,850✔
3583
      if (fold == VCODE_INVALID_REG) {
959,491✔
3584
         if (other->kind == VCODE_OP_LOAD && other->address == var)
618,655✔
3585
            fold = other->result;
17,221✔
3586
         else if (other->kind == VCODE_OP_STORE && other->address == var)
601,434✔
3587
            fold = other->args.items[0];
13,589✔
3588
      }
3589

3590
      if (other->kind == VCODE_OP_INDEX && other->address == var)
959,491✔
3591
         aliased = true;
3592
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
959,428✔
3593
         break;   // Nested call captures variables
3594
      else if (other->kind == VCODE_OP_FILE_READ)
944,474✔
3595
         break;   // May write to variable
3596
   }
3597

3598
   var_t *v = vcode_var_data(var);
89,374✔
3599

3600
   if (fold != VCODE_INVALID_REG && !aliased)
89,374✔
3601
      return fold;
3602

3603
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
58,597✔
3604
   op->address = var;
58,597✔
3605
   op->result  = vcode_add_reg(v->type);
58,597✔
3606

3607
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
58,597✔
3608

3609
   reg_t *r = vcode_reg_data(op->result);
58,597✔
3610
   r->bounds = v->bounds;
58,597✔
3611

3612
   return op->result;
58,597✔
3613
}
3614

3615
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
105,064✔
3616
{
3617
   VCODE_FOR_EACH_OP(other) {
981,578✔
3618
      if (other->kind == VCODE_OP_LOAD_INDIRECT
921,159✔
3619
          && other->args.items[0] == reg) {
121,273✔
3620
         return other->result;
5,621✔
3621
      }
3622
      else if (other->kind == VCODE_OP_FCALL
915,538✔
3623
               || other->kind == VCODE_OP_PCALL
915,538✔
3624
               || other->kind == VCODE_OP_STORE
911,264✔
3625
               || other->kind == VCODE_OP_STORE_INDIRECT
888,322✔
3626
               || other->kind == VCODE_OP_MEMSET
880,945✔
3627
               || other->kind == VCODE_OP_COPY
880,651✔
3628
               || other->kind == VCODE_OP_FILE_READ)
876,526✔
3629
         break;   // May write to this pointer
3630
   }
3631

3632
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
99,443✔
3633
   vcode_add_arg(op, reg);
99,443✔
3634

3635
   vcode_type_t rtype = vcode_reg_type(reg);
99,443✔
3636

3637
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
99,443✔
3638
                "load indirect with non-pointer argument");
3639

3640
   vcode_type_t deref = vtype_pointed(rtype);
99,443✔
3641
   op->result = vcode_add_reg(deref);
99,443✔
3642

3643
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
99,443✔
3644

3645
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
99,443✔
3646

3647
   return op->result;
99,443✔
3648
}
3649

3650
void emit_store(vcode_reg_t reg, vcode_var_t var)
74,521✔
3651
{
3652
   // Any previous store to this variable in this block is dead
3653
   VCODE_FOR_EACH_OP(other) {
1,162,620✔
3654
      if (other->kind == VCODE_OP_STORE && other->address == var) {
1,098,660✔
3655
         other->kind = VCODE_OP_COMMENT;
317✔
3656
         other->comment =
634✔
3657
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
317✔
3658
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
317✔
3659
      }
3660
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
1,098,340✔
3661
         break;   // Needs to get variable for display
3662
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
1,093,250✔
3663
               && other->address == var)
23,983✔
3664
         break;   // Previous value may be used
3665
   }
3666

3667
   var_t *v = vcode_var_data(var);
74,521✔
3668
   reg_t *r = vcode_reg_data(reg);
74,521✔
3669

3670
   op_t *op = vcode_add_op(VCODE_OP_STORE);
74,521✔
3671
   vcode_add_arg(op, reg);
74,521✔
3672
   op->address = var;
74,521✔
3673

3674
   VCODE_ASSERT(vtype_eq(v->type, r->type),
74,521✔
3675
                "variable and stored value do not have same type");
3676
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
74,521✔
3677
}
74,521✔
3678

3679
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
17,804✔
3680
{
3681
   reg_t *p = vcode_reg_data(ptr);
17,804✔
3682
   reg_t *r = vcode_reg_data(reg);
17,804✔
3683

3684
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
17,804✔
3685
   vcode_add_arg(op, reg);
17,804✔
3686
   vcode_add_arg(op, ptr);
17,804✔
3687

3688
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
17,804✔
3689
                "store indirect target is not a pointer");
3690
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
17,804✔
3691
                "pointer and stored value do not have same type");
3692
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
17,804✔
3693
}
17,804✔
3694

3695
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
84,242✔
3696
                              vcode_reg_t locus)
3697
{
3698
   // Reuse any previous operation in this block with the same arguments
3699
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,507,940✔
3700
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
93,327✔
3701
         return other->result;
12,726✔
3702
   }
3703

3704
   op_t *op = vcode_add_op(kind);
71,516✔
3705
   vcode_add_arg(op, lhs);
71,516✔
3706
   vcode_add_arg(op, rhs);
71,516✔
3707
   if (locus != VCODE_INVALID_REG)
71,516✔
3708
      vcode_add_arg(op, locus);
10,848✔
3709

3710
   op->result = vcode_add_reg(vcode_reg_type(lhs));
71,516✔
3711

3712
   vcode_type_t lhs_type = vcode_reg_type(lhs);
71,516✔
3713
   vcode_type_t rhs_type = vcode_reg_type(rhs);
71,516✔
3714

3715
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
71,516✔
3716
                "arguments to %s are not the same type", vcode_op_string(kind));
3717

3718
   return op->result;
3719
}
3720

3721
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
42,475✔
3722
                               vcode_reg_t locus)
3723
{
3724
   int64_t lconst, rconst;
42,475✔
3725
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
42,475✔
3726
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
42,475✔
3727
   if (l_is_const && r_is_const)
42,475✔
3728
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
24,353✔
3729
   else if (r_is_const && rconst == 1)
18,122✔
3730
      return lhs;
3731
   else if (l_is_const && lconst == 1)
6,665✔
3732
      return rhs;
3733
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
6,230✔
3734
      return emit_const(vcode_reg_type(lhs), 0);
42✔
3735

3736
   reg_t *lhs_r = vcode_reg_data(lhs);
6,188✔
3737
   reg_t *rhs_r = vcode_reg_data(rhs);
6,188✔
3738

3739
   vtype_t *bl = vcode_type_data(lhs_r->bounds);
6,188✔
3740
   vtype_t *br = vcode_type_data(rhs_r->bounds);
6,188✔
3741

3742
   vcode_type_t vbounds;
6,188✔
3743
   if (vcode_reg_kind(lhs) == VCODE_TYPE_REAL) {
6,188✔
3744
      const double ll = bl->low * br->low;
569✔
3745
      const double lh = bl->low * br->high;
569✔
3746
      const double hl = bl->high * br->low;
569✔
3747
      const double hh = bl->high * br->high;
569✔
3748

3749
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,419✔
3750
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,413✔
3751

3752
      vbounds = vtype_real(min, max);
569✔
3753
   }
3754
   else {
3755
      const int64_t ll = smul64(bl->low, br->low);
5,619✔
3756
      const int64_t lh = smul64(bl->low, br->high);
5,619✔
3757
      const int64_t hl = smul64(bl->high, br->low);
5,619✔
3758
      const int64_t hh = smul64(bl->high, br->high);
5,619✔
3759

3760
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
5,619✔
3761
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
5,619✔
3762

3763
      vtype_repr_t repr = vtype_repr(lhs_r->type);
5,619✔
3764
      if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
5,619✔
3765
         op = VCODE_OP_MUL;   // Cannot overflow
413✔
3766
         locus = VCODE_INVALID_REG;
413✔
3767
      }
3768

3769
      vbounds = vtype_int(min, max);
5,619✔
3770
   }
3771

3772
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
6,188✔
3773

3774
   if (vbounds != VCODE_INVALID_TYPE)
6,188✔
3775
      vcode_reg_data(reg)->bounds = vbounds;
6,188✔
3776

3777
   return reg;
3778
}
3779

3780
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
40,362✔
3781
{
3782
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
40,362✔
3783
}
3784

3785
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
2,113✔
3786
{
3787
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
2,113✔
3788

3789
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
2,113✔
3790
                "trapping add may only be used with integer types");
3791

3792
   return result;
2,113✔
3793
}
3794

3795
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
891✔
3796
{
3797
   int64_t lconst, rconst;
891✔
3798
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
891✔
3799
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
891✔
3800
   if (l_is_const && r_is_const && rconst != 0)
891✔
3801
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
210✔
3802
   else if (r_is_const && rconst == 1)
681✔
3803
      return lhs;
3804

3805
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
680✔
3806

3807
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
680✔
3808

3809
   if (bl->kind == VCODE_TYPE_INT && r_is_const && rconst != 0) {
680✔
3810
      reg_t *rr = vcode_reg_data(reg);
381✔
3811
      rr->bounds = vtype_int(bl->low / rconst, bl->high / rconst);
381✔
3812
   }
3813
   else if (bl->kind == VCODE_TYPE_REAL) {
299✔
3814
      reg_t *rr = vcode_reg_data(reg);
201✔
3815
      rr->bounds = vtype_real(-INFINITY, INFINITY);
201✔
3816
   }
3817

3818
   return reg;
3819
}
3820

3821
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
80✔
3822
{
3823
   int64_t lconst, rconst;
80✔
3824
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
80✔
3825
       && rconst >= 0)
×
3826
      return emit_const(vcode_reg_type(lhs), ipow(lconst, rconst));
×
3827

3828
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
80✔
3829
}
3830

3831
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
1,283✔
3832
{
3833
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
1,283✔
3834

3835
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
1,283✔
3836
                "trapping exp may only be used with integer types");
3837

3838
   return result;
1,283✔
3839
}
3840

3841
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
410✔
3842
{
3843
   int64_t lconst, rconst;
410✔
3844
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
410✔
3845
       && lconst > 0 && rconst > 0)
14✔
3846
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
3✔
3847

3848
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
407✔
3849
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
407✔
3850

3851
   if (bl->low >= 0 && br->low >= 0) {
407✔
3852
      // If both arguments are non-negative then rem is equivalent and
3853
      // cheaper to compute
3854
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
21✔
3855

3856
      reg_t *rr = vcode_reg_data(reg);
21✔
3857
      rr->bounds = vtype_int(0, br->high - 1);
21✔
3858

3859
      return reg;
21✔
3860
   }
3861
   else
3862
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
386✔
3863
}
3864

3865
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
25✔
3866
{
3867
   int64_t lconst, rconst;
25✔
3868
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
25✔
3869
       && lconst > 0 && rconst > 0)
2✔
3870
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
3871

3872
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
25✔
3873

3874
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
25✔
3875
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
25✔
3876

3877
   if (bl->low >= 0 && br->low >= 0) {
25✔
3878
      reg_t *rr = vcode_reg_data(reg);
×
3879
      rr->bounds = vtype_int(0, br->high - 1);
×
3880
   }
3881

3882
   return reg;
3883
}
3884

3885
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
56,946✔
3886
                               vcode_reg_t locus)
3887
{
3888
   int64_t lconst, rconst;
56,946✔
3889
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
56,946✔
3890
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
56,946✔
3891
   if (l_is_const && r_is_const)
56,946✔
3892
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
18,357✔
3893
   else if (r_is_const && rconst == 0)
38,589✔
3894
      return lhs;
3895
   else if (l_is_const && lconst == 0)
38,586✔
3896
      return rhs;
3897

3898
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
28,687✔
3899
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
28,687✔
3900
      reg_t *lhs_r = vcode_reg_data(lhs);
28,442✔
3901
      reg_t *rhs_r = vcode_reg_data(rhs);
28,442✔
3902

3903
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
28,442✔
3904
      vtype_t *br = vcode_type_data(rhs_r->bounds);
28,442✔
3905

3906
      int64_t rbl = sadd64(bl->low, br->low);
28,442✔
3907
      int64_t rbh = sadd64(bl->high, br->high);
28,442✔
3908

3909
      vtype_repr_t repr = vtype_repr(lhs_r->type);
28,442✔
3910
      if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
28,442✔
3911
         op = VCODE_OP_ADD;   // Cannot overflow
95✔
3912
         locus = VCODE_INVALID_REG;
95✔
3913
      }
3914

3915
      vbounds = vtype_int(rbl, rbh);
28,442✔
3916
   }
3917

3918
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
28,687✔
3919

3920
   if (vbounds != VCODE_INVALID_TYPE)
28,687✔
3921
      vcode_reg_data(reg)->bounds = vbounds;
28,442✔
3922

3923
   return reg;
3924
}
3925

3926
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
50,940✔
3927
{
3928
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
50,940✔
3929
}
3930

3931
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
6,006✔
3932
{
3933
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
6,006✔
3934

3935
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
6,006✔
3936
                "trapping add may only be used with integer types");
3937

3938
   return result;
6,006✔
3939
}
3940

3941
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
53,517✔
3942
                               vcode_reg_t locus)
3943
{
3944
   int64_t lconst, rconst;
53,517✔
3945
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
53,517✔
3946
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
53,517✔
3947
   if (l_is_const && r_is_const)
53,517✔
3948
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
15,040✔
3949
   else if (r_is_const && rconst == 0)
38,477✔
3950
      return lhs;
3951
   else if (l_is_const && lconst == 0)
36,433✔
3952
      return emit_neg(rhs);
833✔
3953

3954
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
35,600✔
3955
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
35,600✔
3956
      reg_t *lhs_r = vcode_reg_data(lhs);
35,324✔
3957
      reg_t *rhs_r = vcode_reg_data(rhs);
35,324✔
3958

3959
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
35,324✔
3960
      vtype_t *br = vcode_type_data(rhs_r->bounds);
35,324✔
3961

3962
      int64_t rbl = ssub64(bl->low, br->high);
35,324✔
3963
      int64_t rbh = ssub64(bl->high, br->low);
35,324✔
3964

3965
      vtype_repr_t repr = vtype_repr(lhs_r->type);
35,324✔
3966
      if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
35,324✔
3967
         op = VCODE_OP_SUB;   // Cannot overflow
3,384✔
3968
         locus = VCODE_INVALID_REG;
3,384✔
3969
      }
3970

3971
      vbounds = vtype_int(rbl, rbh);
35,324✔
3972
   }
3973

3974
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
35,600✔
3975

3976
   if (vbounds != VCODE_INVALID_TYPE)
35,600✔
3977
      vcode_reg_data(reg)->bounds = vbounds;
35,324✔
3978

3979
   return reg;
3980
}
3981

3982
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
34,519✔
3983
{
3984
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
34,519✔
3985
}
3986

3987
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
18,998✔
3988
{
3989
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
18,998✔
3990

3991
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
18,998✔
3992
                "trapping sub may only be used with integer types");
3993

3994
   return result;
18,998✔
3995
}
3996

3997
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
3998
{
3999
   switch (vtype_kind(var->type)) {
4000
   case VCODE_TYPE_CARRAY:
4001
      op->type = vtype_pointer(vtype_elem(var->type));
4002
      op->result = vcode_add_reg(op->type);
4003
      vcode_reg_data(op->result)->bounds = vtype_bounds(var->type);
4004
      break;
4005

4006
   case VCODE_TYPE_RECORD:
4007
      op->type = vtype_pointer(var->type);
4008
      op->result = vcode_add_reg(op->type);
4009
      break;
4010

4011
   case VCODE_TYPE_INT:
4012
   case VCODE_TYPE_FILE:
4013
   case VCODE_TYPE_ACCESS:
4014
   case VCODE_TYPE_REAL:
4015
   case VCODE_TYPE_UARRAY:
4016
   case VCODE_TYPE_POINTER:
4017
   case VCODE_TYPE_SIGNAL:
4018
   case VCODE_TYPE_CONTEXT:
4019
   case VCODE_TYPE_OFFSET:
4020
      op->type = vtype_pointer(var->type);
4021
      op->result = vcode_add_reg(op->type);
4022
      vcode_reg_data(op->result)->bounds = var->bounds;
4023
      break;
4024

4025
   default:
4026
      VCODE_ASSERT(false, "variable %s cannot be indexed",
4027
                   istr(var->name));
4028
   }
4029
}
4030

4031
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
18,813✔
4032
{
4033
   // Try to find a previous index of this var by this offset
4034
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
634,675✔
4035
      if (other->address == var
37,163✔
4036
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
5,659✔
4037
              || (offset != VCODE_INVALID_REG
×
4038
                  && other->args.items[0] == offset)))
×
4039
         return other->result;
5,659✔
4040
   }
4041

4042
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
13,154✔
4043
   op->address = var;
13,154✔
4044

4045
   if (offset != VCODE_INVALID_REG)
13,154✔
4046
      vcode_add_arg(op, offset);
×
4047

4048
   vcode_calculate_var_index_type(op, vcode_var_data(var));
13,154✔
4049

4050
   if (offset != VCODE_INVALID_REG)
13,154✔
4051
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4052
                   "index offset r%d does not have offset type", offset);
4053

4054
   return op->result;
13,154✔
4055
}
4056

4057
vcode_reg_t emit_cast(vcode_type_t type, vcode_type_t bounds, vcode_reg_t reg)
118,583✔
4058
{
4059
   if (vtype_eq(vcode_reg_type(reg), type))
118,583✔
4060
      return reg;
118,583✔
4061

4062
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
102,694✔
4063
   vtype_kind_t to   = vtype_kind(type);
102,694✔
4064

4065
   const bool integral =
205,388✔
4066
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
102,694✔
4067
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
102,694✔
4068

4069
   int64_t value;
102,694✔
4070
   if (integral && vcode_reg_const(reg, &value))
102,694✔
4071
      return emit_const(type, value);
14,122✔
4072

4073
   // Try to find a previous cast of this register to this type
4074
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,514,140✔
4075
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
153,570✔
4076
         return other->result;
33,520✔
4077
   }
4078

4079
   op_t *op = vcode_add_op(VCODE_OP_CAST);
55,052✔
4080
   vcode_add_arg(op, reg);
55,052✔
4081
   op->type   = type;
55,052✔
4082
   op->result = vcode_add_reg(type);
55,052✔
4083

4084
   static const vcode_type_t allowed[][2] = {
55,052✔
4085
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4086
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4087
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4088
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4089
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4090
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4091
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4092
   };
4093

4094
   if (from == VCODE_TYPE_INT && bounds == VCODE_INVALID_TYPE) {
55,052✔
4095
      reg_t *rr = vcode_reg_data(op->result);
10,636✔
4096
      rr->bounds = vcode_reg_bounds(reg);
10,636✔
4097
   }
4098
   else if (to == VCODE_TYPE_INT && bounds != VCODE_INVALID_TYPE) {
44,416✔
4099
      reg_t *rr = vcode_reg_data(op->result);
35,747✔
4100
      rr->bounds = bounds;
35,747✔
4101
   }
4102

4103
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
99,853✔
4104
      if (from == allowed[i][0] && to == allowed[i][1])
99,853✔
4105
         return op->result;
4106
   }
4107

4108
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4109
}
4110

4111
void emit_return(vcode_reg_t reg)
70,526✔
4112
{
4113
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
70,526✔
4114
   if (reg != VCODE_INVALID_REG) {
70,526✔
4115
      vcode_add_arg(op, reg);
54,694✔
4116

4117
      const vtype_kind_t rkind = vcode_reg_kind(reg);
54,694✔
4118
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
54,694✔
4119
         vcode_heap_allocate(reg);
14,691✔
4120
         active_unit->flags |= UNIT_ESCAPING_TLAB;
14,691✔
4121
      }
4122

4123
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
54,694✔
4124
                   || active_unit->kind == VCODE_UNIT_THUNK,
4125
                   "returning value fron non-function unit");
4126
      VCODE_ASSERT(vtype_eq(active_unit->result, vcode_reg_type(reg))
54,694✔
4127
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4128
                       && rkind == VCODE_TYPE_ACCESS),
4129
                   "return value incorrect type");
4130
   }
4131
}
70,526✔
4132

4133
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
8,898✔
4134
                         vcode_reg_t values, vcode_reg_t reject,
4135
                         vcode_reg_t after)
4136
{
4137
   int64_t nconst;
8,898✔
4138
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
8,898✔
4139
      emit_comment("Skip empty waveform");
3✔
4140
      return;
3✔
4141
   }
4142

4143
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
8,895✔
4144
   vcode_add_arg(op, nets);
8,895✔
4145
   vcode_add_arg(op, nnets);
8,895✔
4146
   vcode_add_arg(op, values);
8,895✔
4147
   vcode_add_arg(op, reject);
8,895✔
4148
   vcode_add_arg(op, after);
8,895✔
4149

4150
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
8,895✔
4151
                "sched_waveform target is not signal");
4152
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
8,895✔
4153
                "sched_waveform net count is not offset type");
4154
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
8,895✔
4155
                "signal cannot be values argument for sched_waveform");
4156
}
4157

4158
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
36✔
4159
{
4160
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
36✔
4161
   vcode_add_arg(op, nets);
36✔
4162
   vcode_add_arg(op, nnets);
36✔
4163
   vcode_add_arg(op, values);
36✔
4164

4165
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
36✔
4166
                "force target is not signal");
4167
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
36✔
4168
                "force net count is not offset type");
4169
}
36✔
4170

4171
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
12✔
4172
{
4173
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
12✔
4174
   vcode_add_arg(op, nets);
12✔
4175
   vcode_add_arg(op, nnets);
12✔
4176

4177
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
12✔
4178
                "release target is not signal");
4179
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
12✔
4180
                "release net count is not offset type");
4181
}
12✔
4182

4183
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
15✔
4184
                     vcode_reg_t after)
4185
{
4186
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
15✔
4187
   vcode_add_arg(op, nets);
15✔
4188
   vcode_add_arg(op, nnets);
15✔
4189
   vcode_add_arg(op, reject);
15✔
4190
   vcode_add_arg(op, after);
15✔
4191

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

4198
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
73,410✔
4199
{
4200
   int64_t tconst;
73,410✔
4201
   if (vcode_reg_const(test, &tconst)) {
73,410✔
4202
      emit_jump(!!tconst ? btrue : bfalse);
8,427✔
4203
      return;
6,654✔
4204
   }
4205

4206
   op_t *op = vcode_add_op(VCODE_OP_COND);
66,756✔
4207
   vcode_add_arg(op, test);
66,756✔
4208
   vcode_add_target(op, btrue);
66,756✔
4209
   vcode_add_target(op, bfalse);
66,756✔
4210

4211
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
66,756✔
4212
                "cond test is not a bool");
4213
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
66,756✔
4214
                "invalid cond targets");
4215
}
4216

4217
vcode_reg_t emit_neg(vcode_reg_t lhs)
2,654✔
4218
{
4219
   int64_t lconst;
2,654✔
4220
   if (vcode_reg_const(lhs, &lconst))
2,654✔
4221
      return emit_const(vcode_reg_type(lhs), -lconst);
32✔
4222

4223
   op_t *op = vcode_add_op(VCODE_OP_NEG);
2,622✔
4224
   vcode_add_arg(op, lhs);
2,622✔
4225
   op->result = vcode_add_reg(vcode_reg_type(lhs));
2,622✔
4226

4227
   return op->result;
2,622✔
4228
}
4229

4230
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
2,508✔
4231
{
4232
   int64_t lconst;
2,508✔
4233
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
2,508✔
4234
      return emit_const(vcode_reg_type(lhs), -lconst);
877✔
4235
   else if (vcode_type_data(vcode_reg_data(lhs)->bounds)->low >= 0)
1,631✔
4236
      return emit_neg(lhs);   // Cannot overflow
961✔
4237

4238
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
670✔
4239
   vcode_add_arg(op, lhs);
670✔
4240
   vcode_add_arg(op, locus);
670✔
4241

4242
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
670✔
4243
                "locus argument to trap neg must be a debug locus");
4244
   VCODE_ASSERT(vcode_reg_kind(lhs) == VCODE_TYPE_INT,
670✔
4245
                "trapping neg may only be used with integer types");
4246

4247
   return (op->result = vcode_add_reg(vcode_reg_type(lhs)));
670✔
4248
}
4249

4250
vcode_reg_t emit_abs(vcode_reg_t lhs)
179✔
4251
{
4252
   int64_t lconst;
179✔
4253
   if (vcode_reg_const(lhs, &lconst))
179✔
4254
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
3✔
4255

4256
   op_t *op = vcode_add_op(VCODE_OP_ABS);
176✔
4257
   vcode_add_arg(op, lhs);
176✔
4258
   op->result = vcode_add_reg(vcode_reg_type(lhs));
176✔
4259

4260
   return op->result;
176✔
4261
}
4262

4263
void emit_comment(const char *fmt, ...)
92,155✔
4264
{
4265
#ifndef NDEBUG
4266
   va_list ap;
92,155✔
4267
   va_start(ap, fmt);
92,155✔
4268
   vcode_add_op(VCODE_OP_COMMENT)->comment = xvasprintf(fmt, ap);
92,155✔
4269
   va_end(ap);
92,155✔
4270
#endif
4271
}
92,155✔
4272

4273
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
24,580✔
4274
                        vcode_reg_t rfalse)
4275
{
4276
   int64_t tconst;
24,580✔
4277
   if (vcode_reg_const(test, &tconst))
24,580✔
4278
      return !!tconst ? rtrue : rfalse;
3,033✔
4279
   else if (rtrue == rfalse)
21,547✔
4280
      return rtrue;
4281

4282
   // Find a previous identical select
4283
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
524,084✔
4284
      if (other->args.items[0] == test && other->args.items[1] == rtrue
23,001✔
4285
          && other->args.items[2] == rfalse)
3,697✔
4286
         return other->result;
3,633✔
4287
   }
4288

4289
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
17,705✔
4290
   vcode_add_arg(op, test);
17,705✔
4291
   vcode_add_arg(op, rtrue);
17,705✔
4292
   vcode_add_arg(op, rfalse);
17,705✔
4293
   op->result = vcode_add_reg(vcode_reg_type(rtrue));
17,705✔
4294

4295
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
17,705✔
4296
                "select test must have bool type");
4297
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
17,705✔
4298
                "select arguments are not the same type");
4299

4300
   return op->result;
17,705✔
4301
}
4302

4303
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
844✔
4304
{
4305
   switch (op) {
844✔
4306
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
781✔
4307
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
15✔
4308
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
12✔
4309
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
12✔
4310
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
12✔
4311
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
12✔
4312
   default:
×
4313
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
×
4314
   }
4315
}
4316

4317
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
12,160✔
4318
{
4319
   vcode_type_t vtbool = vtype_bool();
12,160✔
4320

4321
   int64_t lconst, rconst;
12,160✔
4322
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
12,160✔
4323
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
12,160✔
4324
   if (l_is_const && r_is_const) {
12,160✔
4325
      switch (op) {
9✔
4326
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
4327
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
4328
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
2✔
4329
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
7✔
4330
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
4331
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
4332
      default:
×
4333
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
×
4334
      }
4335
   }
4336
   else if (l_is_const)
12,151✔
4337
      return emit_logical_identity(op, rhs, !!lconst);
769✔
4338
   else if (r_is_const)
11,382✔
4339
      return emit_logical_identity(op, lhs, !!rconst);
75✔
4340
   else if (lhs == rhs) {
11,307✔
4341
      switch (op) {
15✔
4342
      case VCODE_OP_AND:
4343
      case VCODE_OP_OR:
4344
         return lhs;
4345
      case VCODE_OP_NAND:
6✔
4346
      case VCODE_OP_NOR:
4347
         return emit_not(lhs);
6✔
4348
      case VCODE_OP_XOR:
3✔
4349
         return emit_const(vtbool, 0);
3✔
4350
      case VCODE_OP_XNOR:
×
4351
         return emit_const(vtbool, 1);
×
4352
      default:
×
4353
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
×
4354
      }
4355
   }
4356

4357
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
11,292✔
4358

4359
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
11,292✔
4360
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4361
                "arguments to %s are not boolean", vcode_op_string(op));
4362

4363
   return result;
4364
}
4365

4366
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
4,292✔
4367
{
4368
   return emit_logical(VCODE_OP_OR, lhs, rhs);
4,292✔
4369
}
4370

4371
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
6,912✔
4372
{
4373
   return emit_logical(VCODE_OP_AND, lhs, rhs);
6,912✔
4374
}
4375

4376
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
220✔
4377
{
4378
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
220✔
4379
}
4380

4381
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
221✔
4382
{
4383
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
221✔
4384
}
4385

4386
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
285✔
4387
{
4388
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
285✔
4389
}
4390

4391
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
230✔
4392
{
4393
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
230✔
4394
}
4395

4396
vcode_reg_t emit_not(vcode_reg_t arg)
10,053✔
4397
{
4398
   op_t *op = vcode_add_op(VCODE_OP_NOT);
10,053✔
4399
   vcode_add_arg(op, arg);
10,053✔
4400

4401
   vcode_type_t vtbool = vtype_bool();
10,053✔
4402
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
10,053✔
4403
                "argument to not is not boolean");
4404

4405
   return (op->result = vcode_add_reg(vtbool));
10,053✔
4406
}
4407

4408
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
37,337✔
4409
{
4410
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,088,030✔
4411
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
82,284✔
4412
         bool match = true;
4413
         for (int i = 0; match && i < ndims; i++) {
9,883✔
4414
            match = other->args.items[i*3 + 1] == dims[i].left
4,978✔
4415
               && other->args.items[i*3 + 2] == dims[i].right
4,233✔
4416
               && other->args.items[i*3 + 3] == dims[i].dir;
9,147✔
4417
         }
4418
         if (match)
4,905✔
4419
            return other->result;
4,096✔
4420
      }
4421
   }
4422

4423
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
33,241✔
4424
   vcode_add_arg(op, data);
33,241✔
4425
   for (int i = 0; i < ndims; i++) {
67,950✔
4426
      vcode_add_arg(op, dims[i].left);
34,709✔
4427
      vcode_add_arg(op, dims[i].right);
34,709✔
4428
      vcode_add_arg(op, dims[i].dir);
34,709✔
4429
   }
4430

4431
   vcode_type_t ptr_type = vcode_reg_type(data);
33,241✔
4432
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
33,241✔
4433
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
33,241✔
4434
                "wrapped data is not pointer or signal");
4435

4436
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
66,482✔
4437
      ? vtype_pointed(ptr_type) : ptr_type;
33,241✔
4438

4439
   op->result = vcode_add_reg(
33,241✔
4440
      vtype_uarray(ndims, elem, vcode_reg_bounds(data)));
4441

4442
   return op->result;
33,241✔
4443
}
4444

4445
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
124,997✔
4446
                                  vcode_reg_t array, unsigned dim,
4447
                                  unsigned arg_index)
4448
{
4449
   // Reuse any previous operation in this block with the same arguments
4450
   VCODE_FOR_EACH_OP(other) {
1,842,760✔
4451
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,778,890✔
4452
          && (rtype == VCODE_INVALID_TYPE
47,250✔
4453
              || vtype_eq(rtype, vcode_reg_type(other->result))))
17,465✔
4454
         return other->result;
47,250✔
4455
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,731,640✔
4456
         return other->args.items[1 + (dim * 3) + arg_index];
13,881✔
4457
   }
4458

4459
   op_t *op = vcode_add_op(o);
63,866✔
4460
   vcode_add_arg(op, array);
63,866✔
4461
   op->dim = dim;
63,866✔
4462

4463
   vcode_type_t atype = vcode_reg_type(array);
63,866✔
4464
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
63,866✔
4465
                "cannot use %s with non-uarray type", vcode_op_string(o));
4466

4467
   vtype_t *vt = vcode_type_data(atype);
63,866✔
4468
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
63,866✔
4469

4470
   if (rtype == VCODE_INVALID_TYPE)
63,866✔
4471
      rtype = vtype_offset();
41,477✔
4472

4473
   return (op->result = vcode_add_reg(rtype));
63,866✔
4474
}
4475

4476
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
45,157✔
4477
{
4478
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
45,157✔
4479
                         array, dim, 0);
4480
}
4481

4482
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
35,306✔
4483
{
4484
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
35,306✔
4485
                         array, dim, 1);
4486
}
4487

4488
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
44,534✔
4489
{
4490
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
44,534✔
4491
                         array, dim, 2);
4492
}
4493

4494
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
57,898✔
4495
{
4496
   VCODE_FOR_EACH_OP(other) {
652,898✔
4497
      if (other->kind == VCODE_OP_UARRAY_LEN) {
616,280✔
4498
         if (other->args.items[0] == array && other->dim == dim)
47,975✔
4499
            return other->result;
14,280✔
4500
      }
4501
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
568,305✔
4502
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
7,000✔
4503
                      "array dimension %d out of bounds", dim);
4504

4505
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
7,000✔
4506
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
7,000✔
4507
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
7,000✔
4508
         return emit_range_length(left_reg, right_reg, dir_reg);
7,000✔
4509
      }
4510
   }
4511

4512
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
36,618✔
4513
   vcode_add_arg(op, array);
36,618✔
4514
   op->dim = dim;
36,618✔
4515

4516
   vcode_type_t atype = vcode_reg_type(array);
36,618✔
4517
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
36,618✔
4518
                "cannot use uarray len with non-uarray type");
4519

4520
   vtype_t *vt = vcode_type_data(atype);
36,618✔
4521
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
36,618✔
4522

4523
   return (op->result = vcode_add_reg(vtype_offset()));
36,618✔
4524
}
4525

4526
vcode_reg_t emit_unwrap(vcode_reg_t array)
48,028✔
4527
{
4528
   VCODE_FOR_EACH_OP(other) {
844,946✔
4529
      if (other->kind == VCODE_OP_WRAP && other->result == array)
804,579✔
4530
         return other->args.items[0];
4,678✔
4531
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
799,901✔
4532
         return other->result;
2,983✔
4533
   }
4534

4535
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
40,367✔
4536
   vcode_add_arg(op, array);
40,367✔
4537

4538
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
40,367✔
4539
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
40,367✔
4540
                "unwrap can only only be used with uarray types");
4541

4542
   vcode_type_t elem = vt->elem;
40,367✔
4543

4544
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
40,367✔
4545
      ? elem : vtype_pointer(elem);
40,367✔
4546

4547
   op->result = vcode_add_reg(rtype);
40,367✔
4548

4549
   reg_t *rr = vcode_reg_data(op->result);
40,367✔
4550
   rr->bounds = elem;
40,367✔
4551

4552
   return op->result;
40,367✔
4553
}
4554

4555
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
16,848✔
4556
                            vcode_reg_t dir)
4557
{
4558
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
490,253✔
4559
      if (other->args.items[0] == left
×
4560
          && other->args.items[1] == right
×
4561
          && other->args.items[2] == dir)
×
4562
         return other->result;
×
4563
   }
4564

4565
   int64_t dir_const;
16,848✔
4566
   if (vcode_reg_const(dir, &dir_const)) {
16,848✔
4567
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
12,015✔
4568
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
12,015✔
4569

4570
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
12,015✔
4571
         return emit_const(vtype_bool(), 1);
38✔
4572
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
11,977✔
4573
         return emit_const(vtype_bool(), 0);
3,950✔
4574
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
8,027✔
4575
         return emit_const(vtype_bool(), 1);
46✔
4576
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
7,981✔
4577
         return emit_const(vtype_bool(), 0);
1,797✔
4578
      else if (dir_const == RANGE_TO)
6,184✔
4579
         return emit_cmp(VCODE_CMP_GT, left, right);
1,309✔
4580
      else
4581
         return emit_cmp(VCODE_CMP_GT, right, left);
4,875✔
4582
   }
4583

4584
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
4,833✔
4585
   vcode_add_arg(op, left);
4,833✔
4586
   vcode_add_arg(op, right);
4,833✔
4587
   vcode_add_arg(op, dir);
4,833✔
4588

4589
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
4,833✔
4590
                "range left and right have different types");
4591
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
4,833✔
4592
                "dir argument to range length is not int");
4593

4594
   return (op->result = vcode_add_reg(vtype_bool()));
4,833✔
4595
}
4596

4597
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
25,018✔
4598
                              vcode_reg_t dir)
4599
{
4600
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_LENGTH) {
447,879✔
4601
      if (other->args.items[0] == left
12,439✔
4602
          && other->args.items[1] == right
9,920✔
4603
          && other->args.items[2] == dir)
9,179✔
4604
         return other->result;
9,173✔
4605
   }
4606

4607
   int64_t lconst, rconst, dconst;
15,845✔
4608
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
15,845✔
4609
       && vcode_reg_const(right, &rconst)) {
6,819✔
4610

4611
      int64_t diff;
4,978✔
4612
      if (dconst == RANGE_TO)
4,978✔
4613
         diff = rconst - lconst;
4,665✔
4614
      else
4615
         diff = lconst - rconst;
313✔
4616

4617
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
4,978✔
4618
   }
4619

4620
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
10,867✔
4621
   vcode_add_arg(op, left);
10,867✔
4622
   vcode_add_arg(op, right);
10,867✔
4623
   vcode_add_arg(op, dir);
10,867✔
4624

4625
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
10,867✔
4626
                "range left and right have different types");
4627
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
10,867✔
4628
                "dir argument to range length is not int");
4629

4630
   return (op->result = vcode_add_reg(vtype_offset()));
10,867✔
4631
}
4632

4633
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
41,602✔
4634
{
4635
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
619,551✔
4636
      if (other->hops == hops && other->address == var)
69,025✔
4637
         return other->result;
6,779✔
4638
   }
4639

4640
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
34,823✔
4641
   op->hops    = hops;
34,823✔
4642
   op->address = var;
34,823✔
4643

4644
   VCODE_ASSERT(hops > 0, "invalid hop count");
34,823✔
4645

4646
   vcode_unit_t vu = active_unit;
34,823✔
4647
   for (int i = 0; i < hops; i++) {
76,562✔
4648
      vu = vu->context;
41,739✔
4649
      VCODE_ASSERT(vu, "hop count is greater than depth");
41,739✔
4650
   }
4651

4652
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
34,823✔
4653

4654
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
34,823✔
4655

4656
   return op->result;
34,823✔
4657
}
4658

4659
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
9,881✔
4660
                             vcode_reg_t size, vcode_reg_t value,
4661
                             vcode_reg_t flags, vcode_reg_t locus,
4662
                             vcode_reg_t offset)
4663
{
4664
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
9,881✔
4665
   vcode_add_arg(op, count);
9,881✔
4666
   vcode_add_arg(op, size);
9,881✔
4667
   vcode_add_arg(op, value);
9,881✔
4668
   vcode_add_arg(op, flags);
9,881✔
4669
   vcode_add_arg(op, locus);
9,881✔
4670
   if (offset != VCODE_INVALID_REG)
9,881✔
4671
      vcode_add_arg(op, offset);
3,277✔
4672

4673
   vcode_type_t vtype = vcode_reg_type(value);
9,881✔
4674
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
9,881✔
4675
   VCODE_ASSERT(vtype_eq(vtype, type)
9,881✔
4676
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4677
                "init signal value type does not match signal type");
4678
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
9,881✔
4679
                "locus argument to init signal must be a debug locus");
4680
   VCODE_ASSERT(offset == VCODE_INVALID_REG
9,881✔
4681
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4682
                "init signal offset argument must have pointer type");
4683

4684
   return (op->result = vcode_add_reg(vtype_signal(type)));
9,881✔
4685
}
4686

4687
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
1,942✔
4688
{
4689
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
1,942✔
4690
   vcode_add_arg(op, signal);
1,942✔
4691
   vcode_add_arg(op, resolution);
1,942✔
4692

4693
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
1,942✔
4694
                "signal argument has wrong type");
4695
   VCODE_ASSERT(vcode_reg_kind(resolution) == VCODE_TYPE_RESOLUTION,
1,942✔
4696
                "resolution wrapper argument has wrong type");
4697
}
1,942✔
4698

4699
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
18✔
4700
                                 vcode_reg_t size, vcode_reg_t locus,
4701
                                 vcode_reg_t kind, vcode_reg_t closure)
4702
{
4703
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
18✔
4704
   vcode_add_arg(op, count);
18✔
4705
   vcode_add_arg(op, size);
18✔
4706
   vcode_add_arg(op, locus);
18✔
4707
   vcode_add_arg(op, kind);
18✔
4708
   vcode_add_arg(op, closure);
18✔
4709

4710
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
18✔
4711
                "count argument to implicit signal is not offset");
4712
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
18✔
4713
                "kind argument to implicit signal is not offset");
4714
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
18✔
4715
                "closure argument to implicit signal is not a closure");
4716
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
18✔
4717
                "locus argument to implicit signal must be a debug locus");
4718

4719
   return (op->result = vcode_add_reg(vtype_signal(type)));
18✔
4720
}
4721

4722
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t src_count,
2,930✔
4723
                     vcode_reg_t dst_count, vcode_reg_t conv)
4724
{
4725
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
2,930✔
4726
   vcode_add_arg(op, src);
2,930✔
4727
   vcode_add_arg(op, dst);
2,930✔
4728
   vcode_add_arg(op, src_count);
2,930✔
4729
   vcode_add_arg(op, dst_count);
2,930✔
4730
   if (conv != VCODE_INVALID_REG)
2,930✔
4731
      vcode_add_arg(op, conv);
249✔
4732

4733
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
2,930✔
4734
                "src argument to map signal is not a signal");
4735
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
2,930✔
4736
                "dst argument to map signal is not a signal");
4737
   VCODE_ASSERT(vcode_reg_kind(src_count) == VCODE_TYPE_OFFSET,
2,930✔
4738
                "src count argument type to map signal is not offset");
4739
   VCODE_ASSERT(vcode_reg_kind(dst_count) == VCODE_TYPE_OFFSET,
2,930✔
4740
                "dst count argument type to map signal is not offset");
4741
   VCODE_ASSERT(conv == VCODE_INVALID_REG
2,930✔
4742
                || vcode_reg_kind(conv) == VCODE_TYPE_CLOSURE,
4743
                "conv argument type to map signal is not closure");
4744
}
2,930✔
4745

4746
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
179✔
4747
{
4748
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
179✔
4749
   vcode_add_arg(op, src);
179✔
4750
   vcode_add_arg(op, dst);
179✔
4751
   vcode_add_arg(op, count);
179✔
4752

4753
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
179✔
4754
                "dst argument to map const is not a signal");
4755
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
179✔
4756
                "count argument type to map const is not offset");
4757
}
179✔
4758

4759
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
8,707✔
4760
{
4761
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
91,397✔
4762
      if (other->args.items[0] == target && other->args.items[1] == count)
16,208✔
4763
         return;
4764
   }
4765

4766
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
6,714✔
4767
   vcode_add_arg(op, target);
6,714✔
4768
   vcode_add_arg(op, count);
6,714✔
4769

4770
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
6,714✔
4771
                "target argument to drive signal is not a signal");
4772
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
6,714✔
4773
                "count argument type to drive signal is not offset");
4774
}
4775

4776
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
1,831✔
4777
                                    vcode_reg_t ileft, vcode_reg_t nlits)
4778
{
4779
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
100,955✔
4780
      if (other->args.items[0] == closure
1,345✔
4781
          && other->args.items[1] == ileft
1,342✔
4782
          && other->args.items[2] == nlits)
1,342✔
4783
         return other->result;
1,342✔
4784
   }
4785

4786
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
489✔
4787
                "first argument to resolution wrapper must be closure");
4788

4789
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
489✔
4790
   vcode_add_arg(op, closure);
489✔
4791
   vcode_add_arg(op, ileft);
489✔
4792
   vcode_add_arg(op, nlits);
489✔
4793
   op->subkind = VCODE_CC_VHDL;
489✔
4794

4795
   return (op->result = vcode_add_reg(vtype_resolution(type)));
489✔
4796
}
4797

4798
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t atype,
1,969✔
4799
                         vcode_type_t rtype)
4800
{
4801
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
104,556✔
4802
      if (other->func == func && other->subkind == VCODE_CC_VHDL
1,426✔
4803
          && other->args.items[0] == context)
1,363✔
4804
         return other->result;
1,363✔
4805
   }
4806

4807
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
606✔
4808
   vcode_add_arg(op, context);
606✔
4809
   op->func    = func;
606✔
4810
   op->subkind = VCODE_CC_VHDL;
606✔
4811
   op->type    = atype;
606✔
4812

4813
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
606✔
4814
                "invalid closure context argument");
4815

4816
   return (op->result = vcode_add_reg(vtype_closure(rtype)));
606✔
4817
}
4818

4819
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
15,304✔
4820
{
4821
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
20,277✔
4822
      if (other->func == name && other->subkind == VCODE_CC_VHDL)
10,238✔
4823
         return other->result;
5,706✔
4824
   }
4825

4826
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
9,598✔
4827
   op->func    = name;
9,598✔
4828
   op->subkind = VCODE_CC_VHDL;
9,598✔
4829
   if (context != VCODE_INVALID_REG)
9,598✔
4830
      vcode_add_arg(op, context);
92✔
4831

4832
   VCODE_ASSERT(context == VCODE_INVALID_REG
9,598✔
4833
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
4834
                "invalid protected init context argument");
4835
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
9,598✔
4836
                || active_unit->kind == VCODE_UNIT_PACKAGE
4837
                || active_unit->kind == VCODE_UNIT_THUNK,
4838
                "cannot use package init here");
4839
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
9,598✔
4840

4841
   return (op->result = vcode_add_reg(vtype_context(name)));
9,598✔
4842
}
4843

4844
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context)
82✔
4845
{
4846
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
82✔
4847
   vcode_add_arg(op, context);
82✔
4848
   op->func    = vtype_name(type);
82✔
4849
   op->subkind = VCODE_CC_VHDL;
82✔
4850

4851
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
82✔
4852
                "protected init type must be context");
4853
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
82✔
4854
                "invalid protected init context argument");
4855

4856
   return (op->result = vcode_add_reg(type));
82✔
4857
}
4858

4859
void emit_process_init(ident_t name, vcode_reg_t locus)
54✔
4860
{
4861
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
54✔
4862
   vcode_add_arg(op, locus);
54✔
4863
   op->func    = name;
54✔
4864
   op->subkind = VCODE_CC_VHDL;
54✔
4865

4866
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
54✔
4867
                "locus argument to process init must be a debug locus");
4868
}
54✔
4869

4870
void emit_protected_free(vcode_reg_t obj)
7✔
4871
{
4872
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
7✔
4873
   vcode_add_arg(op, obj);
7✔
4874

4875
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
7✔
4876
                "protected object type must be context");
4877
}
7✔
4878

4879
vcode_reg_t emit_context_upref(int hops)
18,237✔
4880
{
4881
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
324,004✔
4882
      if (other->hops == hops)
7,434✔
4883
         return other->result;
7,393✔
4884
   }
4885

4886
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
10,844✔
4887
   op->hops = hops;
10,844✔
4888

4889
   VCODE_ASSERT(hops >= 0, "invalid hop count");
10,844✔
4890

4891
   vcode_unit_t vu = active_unit;
10,844✔
4892
   for (int i = 0; i < hops; i++) {
21,140✔
4893
      vu = vu->context;
10,296✔
4894
      VCODE_ASSERT(vu, "hop count is greater than depth");
10,296✔
4895
   }
4896

4897
   return (op->result = vcode_add_reg(vtype_context(vu->name)));
10,844✔
4898
}
4899

4900
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
454✔
4901
                                    vcode_reg_t len)
4902
{
4903
   op_t *op = vcode_add_op(opkind);
454✔
4904
   vcode_add_arg(op, nets);
454✔
4905
   vcode_add_arg(op, len);
454✔
4906

4907
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
454✔
4908
                "argument to %s is not a signal", vcode_op_string(opkind));
4909

4910
   return (op->result = vcode_add_reg(vtype_bool()));
454✔
4911
}
4912

4913
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
273✔
4914
{
4915
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
273✔
4916
}
4917

4918
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
181✔
4919
{
4920
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
181✔
4921
}
4922

4923
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
56,319✔
4924
{
4925
   // Try scanning backwards through the block for another record ref
4926
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
2,460,290✔
4927
      if (other->args.items[0] == record && other->field == field)
554,618✔
4928
         return other->result;
2,328✔
4929
   }
4930

4931
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
53,991✔
4932
   op->field = field;
53,991✔
4933
   vcode_add_arg(op, record);
53,991✔
4934

4935
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
53,991✔
4936

4937
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
53,991✔
4938
                "argument to record ref must be a pointer");
4939

4940
   vtype_t *rtype = vcode_type_data(rptype->pointed);
53,991✔
4941

4942
   const bool is_signal = rtype->kind == VCODE_TYPE_SIGNAL;
53,991✔
4943
   if (is_signal)
53,991✔
4944
      rtype = vcode_type_data(rtype->base);
×
4945

4946
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
53,991✔
4947
                "argument must be pointer to record or record signal");
4948

4949
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
53,991✔
4950

4951
   vcode_type_t field_type  = rtype->fields.items[field];
53,991✔
4952
   vcode_type_t bounds_type = field_type;
53,991✔
4953
   vcode_type_t result_type = field_type;
53,991✔
4954

4955
   const vtype_kind_t fkind = vtype_kind(field_type);
53,991✔
4956
   if (fkind == VCODE_TYPE_CARRAY)
53,991✔
4957
      result_type = bounds_type = vtype_elem(field_type);
12,758✔
4958
   else if (fkind == VCODE_TYPE_UARRAY) {
41,233✔
4959
      bounds_type = vtype_elem(field_type);
4,815✔
4960
      result_type = field_type;
4,815✔
4961
   }
4962

4963
   if (is_signal)
53,991✔
4964
      result_type = vtype_signal(result_type);
×
4965

4966
   op->result = vcode_add_reg(vtype_pointer(result_type));
53,991✔
4967

4968
   reg_t *rr = vcode_reg_data(op->result);
53,991✔
4969
   rr->bounds = bounds_type;
53,991✔
4970

4971
   return op->result;
53,991✔
4972
}
4973

4974
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
56,423✔
4975
{
4976
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
1,062,680✔
4977
      if (other->args.items[0] == array && other->args.items[1] == offset)
58,616✔
4978
         return other->result;
1,203✔
4979
   }
4980

4981
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
55,220✔
4982
   vcode_add_arg(op, array);
55,220✔
4983
   vcode_add_arg(op, offset);
55,220✔
4984

4985
   vcode_type_t rtype = vcode_reg_type(array);
55,220✔
4986
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
55,220✔
4987
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
4988
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
4989
                "argument to array ref must be a pointer or signal");
4990
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
55,220✔
4991
                "array ref offset argument must have offset type");
4992

4993
   op->result = vcode_add_reg(rtype);
55,220✔
4994

4995
   reg_t *rr = vcode_reg_data(op->result);
55,220✔
4996
   rr->bounds = vcode_reg_bounds(array);
55,220✔
4997

4998
   return op->result;
55,220✔
4999
}
5000

5001
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
23,516✔
5002
{
5003
   int64_t cconst;
23,516✔
5004
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
23,516✔
5005
       && cconst == 0)
10,433✔
5006
      return;
5,658✔
5007
   else if (dest == src)
23,425✔
5008
      return;
5009

5010
   op_t *op = vcode_add_op(VCODE_OP_COPY);
17,858✔
5011
   vcode_add_arg(op, dest);
17,858✔
5012
   vcode_add_arg(op, src);
17,858✔
5013
   if (count != VCODE_INVALID_REG)
17,858✔
5014
      vcode_add_arg(op, count);
15,930✔
5015

5016
   vcode_type_t dtype = vcode_reg_type(dest);
17,858✔
5017
   vcode_type_t stype = vcode_reg_type(src);
17,858✔
5018

5019
   vtype_kind_t dkind = vtype_kind(dtype);
17,858✔
5020
   vtype_kind_t skind = vtype_kind(stype);
17,858✔
5021

5022
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
17,858✔
5023
                "destination type is not a pointer or access");
5024
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
17,858✔
5025
                "source type is not a pointer or access");
5026
   VCODE_ASSERT(vtype_eq(dtype, stype),
17,858✔
5027
                "source and destination types do not match");
5028
   VCODE_ASSERT(count == VCODE_INVALID_REG
17,858✔
5029
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5030
                "count is not offset type");
5031

5032
   op->type = vtype_pointed(dtype);
17,858✔
5033
}
5034

5035
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
5,049✔
5036
{
5037
   VCODE_FOR_EACH_OP(other) {
74,285✔
5038
      if (other->kind == VCODE_OP_CLEAR_EVENT)
69,268✔
5039
         break;
5040
      else if (other->kind == VCODE_OP_SCHED_EVENT
69,238✔
5041
               && other->args.items[0] == nets
4,188✔
5042
               && other->args.items[1] == n_elems)
5✔
5043
         return;
5044
   }
5045

5046
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
5,047✔
5047
   vcode_add_arg(op, nets);
5,047✔
5048
   vcode_add_arg(op, n_elems);
5,047✔
5049

5050
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
5,047✔
5051
                "nets argument to sched event must be signal");
5052
}
5053

5054
void emit_implicit_event(vcode_reg_t nets, vcode_reg_t count, vcode_reg_t wake)
18✔
5055
{
5056
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_IMPLICIT_EVENT) {
243✔
5057
      if (other->args.items[0] == nets && other->args.items[1] == count
×
5058
          && other->args.items[1] == wake)
×
5059
         return;
5060
   }
5061

5062
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_EVENT);
18✔
5063
   vcode_add_arg(op, nets);
18✔
5064
   vcode_add_arg(op, count);
18✔
5065
   vcode_add_arg(op, wake);
18✔
5066

5067
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
18✔
5068
                "nets argument to implicit event must be signal");
5069
   VCODE_ASSERT(vcode_reg_kind(wake) == VCODE_TYPE_SIGNAL,
18✔
5070
                "wake argument to implicit event must be signal");
5071
}
5072

5073
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
733✔
5074
{
5075
   VCODE_FOR_EACH_OP(other) {
3,523✔
5076
      if (other->kind == VCODE_OP_SCHED_EVENT)
2,791✔
5077
         break;
5078
      else if (other->kind == VCODE_OP_CLEAR_EVENT
2,791✔
5079
               && other->args.items[0] == nets
339✔
5080
               && other->args.items[1] == n_elems)
1✔
5081
         return;
5082
   }
5083

5084
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
732✔
5085
   vcode_add_arg(op, nets);
732✔
5086
   vcode_add_arg(op, n_elems);
732✔
5087

5088
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
732✔
5089
                "nets argument to clear event must be signal");
5090
}
5091

5092
void emit_resume(ident_t func)
2,266✔
5093
{
5094
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
2,266✔
5095
   op->func = func;
2,266✔
5096

5097
   block_t *b = &(active_unit->blocks.items[active_block]);
2,266✔
5098
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
2,266✔
5099
}
2,266✔
5100

5101
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
6,260✔
5102
{
5103
   int64_t lconst;
6,260✔
5104
   if (vcode_reg_const(len, &lconst) && lconst == 0)
6,260✔
5105
      return;
17✔
5106

5107
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
6,243✔
5108
   vcode_add_arg(op, ptr);
6,243✔
5109
   vcode_add_arg(op, value);
6,243✔
5110
   vcode_add_arg(op, len);
6,243✔
5111

5112
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
6,243✔
5113
                "target of memset must have pointer type");
5114
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
6,243✔
5115
                "value of memset must have scalar type");
5116
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
6,243✔
5117
                "length of memset must have offset type");
5118
}
5119

5120
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
688✔
5121
               const vcode_block_t *blocks, int ncases)
5122
{
5123
   int64_t cval1, cval2;
688✔
5124
   bool is_const = vcode_reg_const(value, &cval1);
688✔
5125

5126
   for (int i = 0; i < ncases; i++) {
5,488✔
5127
      bool can_fold = false;
4,807✔
5128
      if (cases[i] == value)
4,807✔
5129
         can_fold = true;
5130
      else if (is_const && vcode_reg_const(cases[i], &cval2))
4,807✔
5131
         can_fold = (cval1 == cval2);
10✔
5132

5133
      if (can_fold) {
10✔
5134
         emit_jump(blocks[i]);
7✔
5135
         return;
15✔
5136
      }
5137
   }
5138

5139
   if (is_const) {
681✔
5140
      emit_jump(def);
1✔
5141
      return;
1✔
5142
   }
5143

5144
   op_t *op = vcode_add_op(VCODE_OP_CASE);
680✔
5145
   vcode_add_arg(op, value);
680✔
5146
   vcode_add_target(op, def);
680✔
5147

5148
   for (int i = 0; i < ncases; i++) {
5,477✔
5149
      vcode_add_arg(op, cases[i]);
4,797✔
5150
      vcode_add_target(op, blocks[i]);
4,797✔
5151

5152
#ifdef DEBUG
5153
      for (int j = 0; j < i; j++)
128,061✔
5154
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
123,264✔
5155
#endif
5156
   }
5157
}
5158

5159
vcode_reg_t emit_endfile(vcode_reg_t file)
31✔
5160
{
5161
   op_t *op = vcode_add_op(VCODE_OP_ENDFILE);
31✔
5162
   vcode_add_arg(op, file);
31✔
5163

5164
   VCODE_ASSERT(vtype_kind(vcode_reg_type(file)) == VCODE_TYPE_FILE,
31✔
5165
                "endfile argument must have file type");
5166

5167
   return (op->result = vcode_add_reg(vtype_bool()));
31✔
5168
}
5169

5170
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
151✔
5171
                    vcode_reg_t kind, vcode_reg_t status)
5172
{
5173
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
151✔
5174
   vcode_add_arg(op, file);
151✔
5175
   vcode_add_arg(op, name);
151✔
5176
   vcode_add_arg(op, length);
151✔
5177
   vcode_add_arg(op, kind);
151✔
5178
   if (status != VCODE_INVALID_REG)
151✔
5179
      vcode_add_arg(op, status);
18✔
5180

5181
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
151✔
5182
                "file open first argument must have file pointer type");
5183
}
151✔
5184

5185
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
100✔
5186
{
5187
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
100✔
5188
   vcode_add_arg(op, file);
100✔
5189
   vcode_add_arg(op, value);
100✔
5190
   if (length != VCODE_INVALID_REG)
100✔
5191
      vcode_add_arg(op, length);
64✔
5192

5193
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
100✔
5194
                "file write first argument must have file pointer type");
5195
}
100✔
5196

5197
void emit_file_close(vcode_reg_t file)
122✔
5198
{
5199
   op_t *op = vcode_add_op(VCODE_OP_FILE_CLOSE);
122✔
5200
   vcode_add_arg(op, file);
122✔
5201

5202
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
122✔
5203
                "file close argument must have file pointer type");
5204
}
122✔
5205

5206
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
66✔
5207
                    vcode_reg_t inlen, vcode_reg_t outlen)
5208
{
5209
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
66✔
5210
   vcode_add_arg(op, file);
66✔
5211
   vcode_add_arg(op, ptr);
66✔
5212
   if (inlen != VCODE_INVALID_REG) {
66✔
5213
      vcode_add_arg(op, inlen);
27✔
5214
      if (outlen != VCODE_INVALID_REG)
27✔
5215
         vcode_add_arg(op, outlen);
18✔
5216
   }
5217

5218
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
66✔
5219
                "file read first argument must have file pointer type");
5220
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
66✔
5221
                "file read pointer argument must have pointer type");
5222
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
66✔
5223
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5224
                "file read outlen argument must have pointer type");
5225
}
66✔
5226

5227
vcode_reg_t emit_null(vcode_type_t type)
2,688✔
5228
{
5229
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
106,111✔
5230
      if (vtype_eq(vcode_reg_type(other->result), type))
1,863✔
5231
         return other->result;
977✔
5232
   }
5233

5234
   op_t *op = vcode_add_op(VCODE_OP_NULL);
1,711✔
5235
   op->result = vcode_add_reg(type);
1,711✔
5236

5237
   vtype_kind_t kind = vtype_kind(type);
1,711✔
5238
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
1,711✔
5239
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5240
                "null type must be file, access, context, or pointer");
5241

5242
   return op->result;
5243
}
5244

5245
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
1,146✔
5246
{
5247
   op_t *op = vcode_add_op(VCODE_OP_NEW);
1,146✔
5248
   if (length != VCODE_INVALID_REG)
1,146✔
5249
      vcode_add_arg(op, length);
736✔
5250

5251
   op->result = vcode_add_reg(vtype_access(type));
1,146✔
5252

5253
   vtype_kind_t kind = vtype_kind(type);
1,146✔
5254
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
1,146✔
5255
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5256
                || kind == VCODE_TYPE_REAL,
5257
                "new type must be int, real, record, access, or uarray");
5258
   VCODE_ASSERT(length == VCODE_INVALID_REG
1,146✔
5259
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5260
                "new length must have offset type");
5261

5262
   return op->result;
1,146✔
5263
}
5264

5265
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
1,486✔
5266
{
5267
   VCODE_FOR_EACH_OP(other) {
57,769✔
5268
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
56,591✔
5269
         return;
5270
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
56,396✔
5271
         return;
5272
   }
5273

5274
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
1,178✔
5275
   vcode_add_arg(op, ptr);
1,178✔
5276
   vcode_add_arg(op, locus);
1,178✔
5277

5278
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
1,178✔
5279
                "null check argument must be an access");
5280
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,178✔
5281
                "locus argument to null check must be a debug locus");
5282
}
5283

5284
void emit_deallocate(vcode_reg_t ptr)
255✔
5285
{
5286
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
255✔
5287
   vcode_add_arg(op, ptr);
255✔
5288

5289
   vcode_type_t ptype = vcode_reg_type(ptr);
255✔
5290
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
255✔
5291
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5292
                "deallocate argument must be pointer to access");
5293
}
255✔
5294

5295
vcode_reg_t emit_all(vcode_reg_t reg)
2,831✔
5296
{
5297
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
91,410✔
5298
      if (other->args.items[0] == reg)
6,698✔
5299
         return other->result;
501✔
5300
   }
5301

5302
   op_t *op = vcode_add_op(VCODE_OP_ALL);
2,330✔
5303
   vcode_add_arg(op, reg);
2,330✔
5304

5305
   vcode_type_t vtype = vcode_reg_type(reg);
2,330✔
5306

5307
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
2,330✔
5308
                "all argument must be an access");
5309

5310
   vcode_type_t pointed = vtype_pointed(vtype);
2,330✔
5311
   op->result = vcode_add_reg(vtype_pointer(pointed));
2,330✔
5312

5313
   reg_t *rr = vcode_reg_data(op->result);
2,330✔
5314
   rr->bounds = pointed;
2,330✔
5315

5316
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
2,330✔
5317
                "cannot dereference opaque type");
5318

5319
   return op->result;
5320
}
5321

5322
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
18,584✔
5323
{
5324
   block_t *b = &(active_unit->blocks.items[active_block]);
18,584✔
5325
   for (int i = b->ops.count - 1; i >= 0; i--) {
562,306✔
5326
      const op_t *other = &(b->ops.items[i]);
546,274✔
5327
      if (other->kind == kind && other->args.items[0] == sig)
546,274✔
5328
         return other->result;
2,552✔
5329
   }
5330

5331
   op_t *op = vcode_add_op(kind);
16,032✔
5332
   vcode_add_arg(op, sig);
16,032✔
5333

5334
   vcode_type_t stype = vcode_reg_type(sig);
16,032✔
5335
   op->type = stype;
16,032✔
5336

5337
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
16,032✔
5338
                "argument r%d to resolved is not a signal", sig);
5339

5340
   vcode_type_t rtype = vtype_base(stype);
16,032✔
5341

5342
   const vtype_kind_t rkind = vtype_kind(rtype);
16,032✔
5343
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
16,032✔
5344
      rtype = vtype_elem(rtype);
×
5345

5346
   VCODE_ASSERT(vtype_is_scalar(rtype),
16,032✔
5347
                "resolved signal base type must be scalar");
5348

5349
   op->result = vcode_add_reg(vtype_pointer(rtype));
16,032✔
5350

5351
   reg_t *rr = vcode_reg_data(op->result);
16,032✔
5352
   rr->bounds = rtype;
16,032✔
5353

5354
   return op->result;
16,032✔
5355
}
5356

5357
vcode_reg_t emit_resolved(vcode_reg_t sig)
18,485✔
5358
{
5359
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
18,485✔
5360
}
5361

5362
vcode_reg_t emit_last_value(vcode_reg_t sig)
99✔
5363
{
5364
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
99✔
5365
}
5366

5367
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
64✔
5368
{
5369
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
64✔
5370
   vcode_add_arg(op, signal);
64✔
5371
   if (len != VCODE_INVALID_REG)
64✔
5372
      vcode_add_arg(op, len);
34✔
5373

5374
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
64✔
5375
                "signal argument to last event must have signal type");
5376
   VCODE_ASSERT(len == VCODE_INVALID_REG
64✔
5377
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5378
                "length argument to last event must have offset type");
5379

5380
   return (op->result = vcode_add_reg(vtype_time()));
64✔
5381
}
5382

5383
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
36✔
5384
{
5385
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
36✔
5386
   vcode_add_arg(op, signal);
36✔
5387
   if (len != VCODE_INVALID_REG)
36✔
5388
      vcode_add_arg(op, len);
27✔
5389

5390
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5391
                "signal argument to last active must have signal type");
5392
   VCODE_ASSERT(len == VCODE_INVALID_REG
36✔
5393
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5394
                "length argument to last active must have offset type");
5395

5396
   return (op->result = vcode_add_reg(vtype_time()));
36✔
5397
}
5398

5399
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
2,588✔
5400
{
5401
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
2,588✔
5402
   vcode_add_arg(op, signal);
2,588✔
5403
   vcode_add_arg(op, locus);
2,588✔
5404

5405
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
2,588✔
5406
                "signal argument must have signal type");
5407
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,588✔
5408
                "locus argument must have debug locus type");
5409
}
2,588✔
5410

5411
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
30✔
5412
{
5413
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
30✔
5414
   vcode_add_arg(op, signal);
30✔
5415
   vcode_add_arg(op, len);
30✔
5416

5417
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
30✔
5418
                "signal argument to last active must have signal type");
5419
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
30✔
5420
                "length argument to last active must have offset type");
5421

5422
   return (op->result = vcode_add_reg(vtype_bool()));
30✔
5423
}
5424

5425
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
24✔
5426
{
5427
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
24✔
5428
   vcode_add_arg(op, signal);
24✔
5429
   if (len != VCODE_INVALID_REG)
24✔
5430
      vcode_add_arg(op, len);
3✔
5431

5432
   vcode_type_t signal_type = vcode_reg_type(signal);
24✔
5433

5434
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
24✔
5435
                "signal argument to last active must have signal type");
5436
   VCODE_ASSERT(len == VCODE_INVALID_REG
24✔
5437
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5438
                "length argument to last active must have offset type");
5439

5440
   vcode_type_t base_type = vtype_base(signal_type);
24✔
5441
   op->result = vcode_add_reg(vtype_pointer(base_type));
24✔
5442

5443
   reg_t *rr = vcode_reg_data(op->result);
24✔
5444
   rr->bounds = base_type;
24✔
5445

5446
   return op->result;
24✔
5447
}
5448

5449
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
19,016✔
5450
                       vcode_reg_t dim)
5451
{
5452
   if (rlen == llen)
19,016✔
5453
      return;
5454

5455
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
164,850✔
5456
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
2,815✔
5457
         return;
5458
   }
5459

5460
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
7,122✔
5461
   vcode_add_arg(op, llen);
7,122✔
5462
   vcode_add_arg(op, rlen);
7,122✔
5463
   vcode_add_arg(op, locus);
7,122✔
5464
   if (dim != VCODE_INVALID_REG)
7,122✔
5465
      vcode_add_arg(op, dim);
50✔
5466

5467
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
7,122✔
5468
                "locus argument to length check must be a debug locus");
5469
}
5470

5471
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
1,283✔
5472
{
5473
   int64_t cval;
1,283✔
5474
   if (vcode_reg_const(exp, &cval) && cval >= 0)
1,283✔
5475
      return;
775✔
5476

5477
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
3,194✔
5478
      if (other->args.items[0] == exp)
3✔
5479
         return;
5480
   }
5481

5482
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
508✔
5483
   vcode_add_arg(op, exp);
508✔
5484
   vcode_add_arg(op, locus);
508✔
5485

5486
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
508✔
5487
                "exp argument to exponent check must be a integer");
5488
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
508✔
5489
                "locus argument to exponent check must be a debug locus");
5490
}
5491

5492
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
835✔
5493
{
5494
   int64_t cval;
835✔
5495
   if (vcode_reg_const(denom, &cval) && cval != 0)
835✔
5496
      return;
728✔
5497

5498
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
1,394✔
5499
      if (other->args.items[0] == denom)
32✔
5500
         return;
5501
   }
5502

5503
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
107✔
5504
   vcode_add_arg(op, denom);
107✔
5505
   vcode_add_arg(op, locus);
107✔
5506

5507
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
107✔
5508
                "denom argument to zero check must be a integer");
5509
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
107✔
5510
                "locus argument to zero check must be a debug locus");
5511
}
5512

5513
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
95,934✔
5514
                              vcode_reg_t left, vcode_reg_t right,
5515
                              vcode_reg_t dir, vcode_reg_t locus,
5516
                              vcode_reg_t hint)
5517
{
5518
   if (reg == left || reg == right) {
95,934✔
5519
      emit_comment("Elided trivial bounds check for r%d", reg);
21,043✔
5520
      return;
103,381✔
5521
   }
5522

5523
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,742,620✔
5524
      if (other->args.items[0] == reg && other->args.items[1] == left
9,063✔
5525
          && other->args.items[2] == right && other->args.items[3] == dir)
377✔
5526
         return;
5527
   }
5528

5529
   int64_t dconst;
74,516✔
5530
   if (vcode_reg_const(dir, &dconst)) {
74,516✔
5531
      int64_t lconst, rconst;
66,478✔
5532
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
66,478✔
5533
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
61,236✔
5534
            || (dconst == RANGE_DOWNTO && rconst > lconst);
124,019✔
5535

5536
         if (is_null) {
62,783✔
5537
            emit_comment("Elided bounds check for null range");
×
5538
            return;
60,920✔
5539
         }
5540

5541
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
62,783✔
5542

5543
         const bool ok_static =
125,566✔
5544
            (dconst == RANGE_TO
5545
             && bounds->low >= lconst && bounds->high <= rconst)
61,236✔
5546
            || (dconst == RANGE_DOWNTO
67,680✔
5547
                && bounds->low >= rconst && bounds->high <= lconst);
1,547✔
5548

5549
         if (ok_static) {
62,783✔
5550
            emit_comment("Elided bounds check for r%d", reg);
57,779✔
5551
            return;
57,779✔
5552
         }
5553
      }
5554
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
3,695✔
5555
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
3,419✔
5556
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
3,419✔
5557

5558
         assert(lbounds->kind == VCODE_TYPE_REAL);
3,419✔
5559
         assert(rbounds->kind == VCODE_TYPE_REAL);
3,419✔
5560

5561
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
3,419✔
5562
         assert(bounds->kind == VCODE_TYPE_REAL);
3,419✔
5563

5564
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
3,419✔
5565
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
3,141✔
5566
            // Covers the complete double range so can never overflow
5567
            emit_comment("Elided real bounds check for r%d", reg);
3,141✔
5568
            return;
3,141✔
5569
         }
5570
      }
5571
   }
5572

5573
   op_t *op = vcode_add_op(kind);
13,596✔
5574
   vcode_add_arg(op, reg);
13,596✔
5575
   vcode_add_arg(op, left);
13,596✔
5576
   vcode_add_arg(op, right);
13,596✔
5577
   vcode_add_arg(op, dir);
13,596✔
5578
   vcode_add_arg(op, locus);
13,596✔
5579
   vcode_add_arg(op, hint);
13,596✔
5580

5581
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
13,596✔
5582
                "locus argument to bounds check must be a debug locus");
5583
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
13,596✔
5584
                "hint argument to bounds check must be a debug locus");
5585
}
5586

5587
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
61,053✔
5588
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5589
{
5590
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
61,053✔
5591
}
61,053✔
5592

5593
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
34,881✔
5594
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5595
{
5596
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
34,881✔
5597
}
34,881✔
5598

5599
void emit_push_scope(vcode_reg_t locus, vcode_type_t type)
895✔
5600
{
5601
   op_t *op = vcode_add_op(VCODE_OP_PUSH_SCOPE);
895✔
5602
   vcode_add_arg(op, locus);
895✔
5603
   op->type = type;
895✔
5604

5605
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
895✔
5606
                "locus argument to push scope must be a debug locus");
5607
}
895✔
5608

5609
void emit_pop_scope(void)
895✔
5610
{
5611
   vcode_add_op(VCODE_OP_POP_SCOPE);
895✔
5612
}
895✔
5613

5614
vcode_reg_t emit_debug_locus(ident_t unit, ptrdiff_t offset)
211,399✔
5615
{
5616
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
5,340,580✔
5617
      if (other->ident == unit && other->tag == offset)
846,810✔
5618
         return other->result;
25,267✔
5619
   }
5620

5621
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
186,132✔
5622
   op->ident = unit;
186,132✔
5623
   op->value = offset;
186,132✔
5624

5625
   return (op->result = vcode_add_reg(vtype_debug_locus()));
186,132✔
5626
}
5627

5628
void emit_debug_out(vcode_reg_t reg)
×
5629
{
5630
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
5631
   vcode_add_arg(op, reg);
×
5632
}
×
5633

5634
void emit_cover_stmt(uint32_t tag)
600✔
5635
{
5636
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
600✔
5637
   op->tag = tag;
600✔
5638
}
600✔
5639

5640
void emit_cover_branch(vcode_reg_t test, uint32_t tag, uint32_t flags)
284✔
5641
{
5642
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
284✔
5643
   vcode_add_arg(op, test);
284✔
5644
   op->tag = tag;
284✔
5645
   op->subkind = flags;
284✔
5646
}
284✔
5647

5648
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
269✔
5649
{
5650
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
269✔
5651
   vcode_add_arg(op, signal);
269✔
5652
   op->tag = tag;
269✔
5653
}
269✔
5654

5655
void emit_cover_expr(vcode_reg_t new_mask, uint32_t tag)
303✔
5656
{
5657
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
303✔
5658
   vcode_add_arg(op, new_mask);
303✔
5659
   op->tag = tag;
303✔
5660
}
303✔
5661

5662
void emit_unreachable(vcode_reg_t locus)
104✔
5663
{
5664
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
104✔
5665
   if (locus != VCODE_INVALID_REG)
104✔
5666
      vcode_add_arg(op, locus);
104✔
5667
}
104✔
5668

5669
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
1,272✔
5670
{
5671
   active_unit->flags |= UNIT_UNDEFINED;
1,272✔
5672

5673
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
1,272✔
5674
   op->result = vcode_add_reg(type);
1,272✔
5675
   vcode_reg_data(op->result)->bounds = bounds;
1,272✔
5676

5677
   return op->result;
1,272✔
5678
}
5679

5680
vcode_reg_t emit_strconv(vcode_reg_t ptr, vcode_reg_t len, vcode_reg_t used_ptr,
103✔
5681
                         vcode_type_t type)
5682
{
5683
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_STRCONV) {
339✔
5684
      if (other->args.items[0] == ptr && other->args.items[1] == len
×
5685
          && other->type == type && used_ptr == VCODE_INVALID_REG)
×
5686
         return other->result;
×
5687
   }
5688

5689
   op_t *op = vcode_add_op(VCODE_OP_STRCONV);
103✔
5690
   vcode_add_arg(op, ptr);
103✔
5691
   vcode_add_arg(op, len);
103✔
5692
   if (used_ptr != VCODE_INVALID_REG)
103✔
5693
      vcode_add_arg(op, used_ptr);
30✔
5694
   op->type = type;
103✔
5695

5696
   VCODE_ASSERT(vcode_reg_kind(ptr) == VCODE_TYPE_POINTER,
103✔
5697
                "strconv ptr argument must be pointer");
5698
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
103✔
5699
                "strconv len argument must be offset");
5700
   VCODE_ASSERT(used_ptr == VCODE_INVALID_REG
103✔
5701
                || vcode_reg_kind(used_ptr) == VCODE_TYPE_POINTER,
5702
                "strconv used_ptr argument must be pointer");
5703
   VCODE_ASSERT(vtype_is_scalar(type), "strconv result must be scalar");
103✔
5704

5705
   return (op->result = vcode_add_reg(type));
103✔
5706
}
5707

5708
vcode_reg_t emit_convstr(vcode_reg_t value)
103✔
5709
{
5710
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONVSTR) {
130✔
5711
      if (other->args.items[0] == value)
×
5712
         return other->result;
×
5713
   }
5714

5715
   op_t *op = vcode_add_op(VCODE_OP_CONVSTR);
103✔
5716
   vcode_add_arg(op, value);
103✔
5717

5718
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
103✔
5719
                "convstr value must be scalar");
5720

5721
   vcode_type_t vchar = vtype_char();
103✔
5722
   return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar)));
103✔
5723
}
5724

5725
vcode_reg_t emit_canon_value(vcode_reg_t ptr, vcode_reg_t len)
283✔
5726
{
5727
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CANON_VALUE) {
999✔
5728
      if (other->args.items[0] == ptr && other->args.items[1] == len)
×
5729
         return other->result;
×
5730
   }
5731

5732
   op_t *op = vcode_add_op(VCODE_OP_CANON_VALUE);
283✔
5733
   vcode_add_arg(op, ptr);
283✔
5734
   vcode_add_arg(op, len);
283✔
5735

5736
   VCODE_ASSERT(vcode_reg_kind(ptr) == VCODE_TYPE_POINTER,
283✔
5737
                "canon value ptr argument must be pointer");
5738
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
283✔
5739
                "canon value len argument must be offset");
5740

5741
   vcode_type_t vchar = vtype_char();
283✔
5742
   return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar)));
283✔
5743
}
5744

5745
void emit_debug_info(const loc_t *loc)
1,807,570✔
5746
{
5747
   if (!loc_invalid_p(loc))
1,807,570✔
5748
      vcode_block_data()->last_loc = *loc;
1,712,500✔
5749
}
1,807,570✔
5750

5751
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
3,729✔
5752
{
5753
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
114,351✔
5754
      if (other->args.items[0] == context && other->ident == name)
5,706✔
5755
         return other->result;
1,285✔
5756
   }
5757

5758
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
2,444✔
5759
   vcode_add_arg(op, context);
2,444✔
5760
   op->ident = name;
2,444✔
5761

5762
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
2,444✔
5763
                "first argument to link var must be context");
5764

5765
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
2,444✔
5766
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
75✔
5767
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
75✔
5768
   }
5769
   else {
5770
      op->result = vcode_add_reg(vtype_pointer(type));
2,369✔
5771
      vcode_reg_data(op->result)->bounds = type;
2,369✔
5772
   }
5773

5774
   return op->result;
2,444✔
5775
}
5776

5777
vcode_reg_t emit_link_package(ident_t name)
16,883✔
5778
{
5779
   VCODE_FOR_EACH_OP(other) {
638,104✔
5780
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
628,908✔
5781
         return other->result;
4,612✔
5782
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
624,296✔
5783
         return other->result;
3,075✔
5784
   }
5785

5786
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
9,196✔
5787
   op->ident = name;
9,196✔
5788

5789
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
9,196✔
5790

5791
   return (op->result = vcode_add_reg(vtype_context(name)));
9,196✔
5792
}
5793

5794
vcode_reg_t emit_link_instance(ident_t name, vcode_reg_t locus)
99✔
5795
{
5796
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_INSTANCE) {
519✔
5797
      if (other->ident == name)
39✔
5798
         return other->result;
24✔
5799
   }
5800

5801
   op_t *op = vcode_add_op(VCODE_OP_LINK_INSTANCE);
75✔
5802
   vcode_add_arg(op, locus);
75✔
5803
   op->ident = name;
75✔
5804

5805
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
75✔
5806
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
75✔
5807
                "locus argument to link instnance must be a debug locus");
5808

5809
   return (op->result = vcode_add_reg(vtype_context(name)));
75✔
5810
}
5811

5812
static void vcode_write_unit(vcode_unit_t unit, fbuf_t *f,
16,450✔
5813
                             ident_wr_ctx_t ident_wr_ctx,
5814
                             loc_wr_ctx_t *loc_wr_ctx)
5815
{
5816
   write_u8(unit->kind, f);
17,050✔
5817
   ident_write(unit->name, ident_wr_ctx);
17,050✔
5818
   fbuf_put_int(f, unit->result);
17,050✔
5819
   fbuf_put_int(f, unit->flags);
17,050✔
5820
   fbuf_put_int(f, unit->depth);
17,050✔
5821

5822
   if (unit->offset < 0) {
17,050✔
5823
      object_t *obj = object_from_locus(unit->module, unit->offset, NULL);
×
5824
      object_locus(obj, &unit->module, &unit->offset);
×
5825
   }
5826

5827
   ident_write(unit->module, ident_wr_ctx);
17,050✔
5828
   fbuf_put_uint(f, unit->offset);
17,050✔
5829

5830
   if (unit->context != NULL) {
17,050✔
5831
      vcode_select_unit(unit);
16,456✔
5832
      vcode_select_unit(vcode_unit_context());
16,456✔
5833
      ident_write(vcode_unit_name(), ident_wr_ctx);
16,456✔
5834
      vcode_close();
16,456✔
5835
   }
5836
   else
5837
      ident_write(NULL, ident_wr_ctx);
594✔
5838

5839
   fbuf_put_uint(f, unit->blocks.count);
17,050✔
5840
   for (unsigned i = 0; i < unit->blocks.count; i++) {
120,691✔
5841
      const block_t *b = &(unit->blocks.items[i]);
103,641✔
5842
      fbuf_put_uint(f, b->ops.count);
103,641✔
5843

5844
      for (unsigned j = 0; j < b->ops.count; j++) {
1,166,410✔
5845
         op_t *op = &(b->ops.items[j]);
1,062,770✔
5846

5847
         if (op->kind == VCODE_OP_DEBUG_LOCUS && op->value < 0) {
1,062,770✔
5848
            object_t *obj = object_from_locus(op->ident, op->value, NULL);
×
5849
            object_locus(obj, &op->ident, (ptrdiff_t *)&op->value);
×
5850
         }
5851

5852
         fbuf_put_uint(f, op->kind);
1,062,770✔
5853
         fbuf_put_uint(f, op->result);
1,062,770✔
5854
         loc_write(&(op->loc), loc_wr_ctx);
1,062,770✔
5855

5856
         fbuf_put_uint(f, op->args.count);
1,062,770✔
5857
         for (unsigned k = 0; k < op->args.count; k++)
2,986,630✔
5858
            fbuf_put_uint(f, op->args.items[k]);
1,923,860✔
5859

5860
         if (OP_HAS_TARGET(op->kind)) {
1,062,770✔
5861
            fbuf_put_uint(f, op->targets.count);
75,025✔
5862
            for (unsigned k = 0; k < op->targets.count; k++)
198,306✔
5863
               fbuf_put_uint(f, op->targets.items[k]);
123,281✔
5864
         }
5865

5866
         if (OP_HAS_TYPE(op->kind))
1,062,770✔
5867
            fbuf_put_uint(f, op->type);
247,950✔
5868
         if (OP_HAS_ADDRESS(op->kind))
1,062,770✔
5869
            fbuf_put_uint(f, op->address);
95,998✔
5870
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
1,062,770✔
5871
            ident_write(op->func, ident_wr_ctx);
57,527✔
5872
         if (OP_HAS_SUBKIND(op->kind))
1,062,770✔
5873
            fbuf_put_uint(f, op->subkind);
24,420✔
5874
         if (OP_HAS_CMP(op->kind))
1,062,770✔
5875
            fbuf_put_uint(f, op->cmp);
41,313✔
5876
         if (OP_HAS_VALUE(op->kind))
1,062,770✔
5877
            fbuf_put_int(f, op->value);
211,704✔
5878
         if (OP_HAS_REAL(op->kind))
1,062,770✔
5879
            write_double(op->real, f);
3,869✔
5880
         if (OP_HAS_COMMENT(op->kind))
1,062,770✔
5881
            ;   // Do not save comments
5882
         if (OP_HAS_DIM(op->kind))
1,062,770✔
5883
            fbuf_put_uint(f, op->dim);
73,523✔
5884
         if (OP_HAS_HOPS(op->kind))
1,062,770✔
5885
            fbuf_put_uint(f, op->hops);
14,599✔
5886
         if (OP_HAS_FIELD(op->kind))
1,062,770✔
5887
            fbuf_put_uint(f, op->field);
23,262✔
5888
         if (OP_HAS_TAG(op->kind))
1,062,770✔
5889
            fbuf_put_uint(f, op->tag);
×
5890
      }
5891
   }
5892

5893
   fbuf_put_uint(f, unit->regs.count);
17,050✔
5894
   for (unsigned i = 0; i < unit->regs.count; i++) {
959,077✔
5895
      const reg_t *r = &(unit->regs.items[i]);
942,027✔
5896
      fbuf_put_uint(f, r->type);
942,027✔
5897
      fbuf_put_uint(f, r->bounds);
942,027✔
5898
   }
5899

5900
   fbuf_put_uint(f, unit->types.count);
17,050✔
5901
   for (unsigned i = 0; i < unit->types.count; i++) {
294,639✔
5902
      const vtype_t *t = &(unit->types.items[i]);
277,589✔
5903
      fbuf_put_uint(f, t->kind);
277,589✔
5904
      switch (t->kind) {
277,589✔
5905
      case VCODE_TYPE_INT:
187,999✔
5906
      case VCODE_TYPE_OFFSET:
5907
         fbuf_put_int(f, t->repr);
187,999✔
5908
         fbuf_put_int(f, t->low);
187,999✔
5909
         fbuf_put_int(f, t->high);
187,999✔
5910
         break;
187,999✔
5911

5912
      case VCODE_TYPE_REAL:
6,302✔
5913
         write_double(t->rlow, f);
6,302✔
5914
         write_double(t->rhigh, f);
6,302✔
5915
         break;
6,302✔
5916

5917
      case VCODE_TYPE_CARRAY:
24,899✔
5918
      case VCODE_TYPE_UARRAY:
5919
         fbuf_put_uint(f, t->dims);
24,899✔
5920
         fbuf_put_uint(f, t->size);
24,899✔
5921
         fbuf_put_uint(f, t->elem);
24,899✔
5922
         fbuf_put_uint(f, t->bounds);
24,899✔
5923
         break;
24,899✔
5924

5925
      case VCODE_TYPE_ACCESS:
24,098✔
5926
      case VCODE_TYPE_POINTER:
5927
         fbuf_put_uint(f, t->pointed);
24,098✔
5928
         break;
24,098✔
5929

5930
      case VCODE_TYPE_FILE:
1,443✔
5931
      case VCODE_TYPE_SIGNAL:
5932
      case VCODE_TYPE_RESOLUTION:
5933
      case VCODE_TYPE_CLOSURE:
5934
         fbuf_put_uint(f, t->base);
1,443✔
5935
         break;
1,443✔
5936

5937
      case VCODE_TYPE_OPAQUE:
5938
      case VCODE_TYPE_DEBUG_LOCUS:
5939
         break;
5940

5941
      case VCODE_TYPE_CONTEXT:
20,457✔
5942
         ident_write(t->name, ident_wr_ctx);
20,457✔
5943
         break;
20,457✔
5944

5945
      case VCODE_TYPE_RECORD:
4,595✔
5946
         ident_write(t->name, ident_wr_ctx);
4,595✔
5947
         fbuf_put_uint(f, t->fields.count);
4,595✔
5948
         for (unsigned j = 0; j < t->fields.count; j++)
25,897✔
5949
            fbuf_put_uint(f, t->fields.items[j]);
21,302✔
5950
         break;
5951
      }
5952
   }
277,589✔
5953

5954
   fbuf_put_uint(f, unit->vars.count);
17,050✔
5955
   for (unsigned i = 0; i < unit->vars.count; i++) {
43,765✔
5956
      const var_t *v = &(unit->vars.items[i]);
26,715✔
5957
      fbuf_put_uint(f, v->type);
26,715✔
5958
      fbuf_put_uint(f, v->bounds);
26,715✔
5959
      ident_write(v->name, ident_wr_ctx);
26,715✔
5960
      fbuf_put_uint(f, v->flags);
26,715✔
5961
   }
5962

5963
   fbuf_put_uint(f, unit->params.count);
17,050✔
5964
   for (unsigned i = 0; i < unit->params.count; i++) {
66,270✔
5965
      const param_t *p = &(unit->params.items[i]);
49,220✔
5966
      fbuf_put_uint(f, p->type);
49,220✔
5967
      fbuf_put_uint(f, p->bounds);
49,220✔
5968
      ident_write(p->name, ident_wr_ctx);
49,220✔
5969
      fbuf_put_uint(f, p->reg);
49,220✔
5970
   }
5971

5972
   if (unit->next != NULL)
17,050✔
5973
      vcode_write_unit(unit->next, f, ident_wr_ctx, loc_wr_ctx);
15,856✔
5974

5975
   if (unit->children != NULL)
17,050✔
5976
      vcode_write_unit(unit->children, f, ident_wr_ctx, loc_wr_ctx);
5977
}
16,450✔
5978

5979
void vcode_write(vcode_unit_t unit, fbuf_t *f, ident_wr_ctx_t ident_ctx,
594✔
5980
                 loc_wr_ctx_t *loc_ctx)
5981
{
5982
   assert(unit->context == NULL);
594✔
5983

5984
   write_u8(VCODE_VERSION, f);
594✔
5985

5986
   vcode_write_unit(unit, f, ident_ctx, loc_ctx);
594✔
5987
   write_u8(0xff, f);  // End marker
594✔
5988
}
594✔
5989

5990
static vcode_unit_t vcode_read_unit(fbuf_t *f, ident_rd_ctx_t ident_rd_ctx,
326,530✔
5991
                                    loc_rd_ctx_t *loc_rd_ctx)
5992
{
5993
   const uint8_t marker = read_u8(f);
326,530✔
5994
   if (marker == 0xff)
326,530✔
5995
      return false;
5996

5997
   vcode_unit_t unit = xcalloc(sizeof(struct _vcode_unit));
322,373✔
5998
   unit->kind   = marker;
322,373✔
5999
   unit->name   = ident_read(ident_rd_ctx);
322,373✔
6000
   unit->result = fbuf_get_int(f);
322,373✔
6001
   unit->flags  = fbuf_get_int(f);
322,373✔
6002
   unit->depth  = fbuf_get_int(f);
322,373✔
6003
   unit->module = ident_read(ident_rd_ctx);
322,373✔
6004
   unit->offset = fbuf_get_uint(f);
322,373✔
6005

6006
   ident_t context_name = ident_read(ident_rd_ctx);
322,373✔
6007
   if (context_name != NULL) {
322,373✔
6008
      unit->context = vcode_find_unit(context_name);
318,216✔
6009
      if (unit->context == NULL)
318,216✔
6010
         fatal("%s references nonexistent context %s", fbuf_file_name(f),
×
6011
               istr(context_name));
6012

6013
      vcode_add_child(unit->context, unit);
318,216✔
6014
   }
6015
   else
6016
      unit->context = NULL;
4,157✔
6017

6018
   block_array_resize(&(unit->blocks), fbuf_get_uint(f), 0);
322,373✔
6019
   for (unsigned i = 0; i < unit->blocks.count; i++) {
2,564,470✔
6020
      block_t *b = &(unit->blocks.items[i]);
2,242,100✔
6021
      op_array_resize(&(b->ops), fbuf_get_uint(f), 0);
2,242,100✔
6022

6023
      for (unsigned j = 0; j < b->ops.count; j++) {
24,313,400✔
6024
         op_t *op = &(b->ops.items[j]);
22,071,300✔
6025

6026
         op->kind = fbuf_get_uint(f);
22,071,300✔
6027
         op->result = fbuf_get_uint(f);
22,071,300✔
6028
         loc_read(&(op->loc), loc_rd_ctx);
22,071,300✔
6029

6030
         vcode_reg_array_resize(&(op->args), fbuf_get_uint(f), 0);
22,071,300✔
6031
         for (unsigned k = 0; k < op->args.count; k++)
50,171,300✔
6032
            op->args.items[k] = fbuf_get_uint(f);
28,100,000✔
6033

6034
         if (OP_HAS_TARGET(op->kind)) {
22,071,300✔
6035
            vcode_block_array_resize(&(op->targets), fbuf_get_uint(f), 0);
920,698✔
6036
            for (unsigned k = 0; k < op->targets.count; k++)
3,298,840✔
6037
               op->targets.items[k] = fbuf_get_uint(f);
2,378,140✔
6038
         }
6039

6040
         if (OP_HAS_TYPE(op->kind))
22,071,300✔
6041
            op->type = fbuf_get_uint(f);
9,959,260✔
6042
         if (OP_HAS_ADDRESS(op->kind))
22,071,300✔
6043
            op->address = fbuf_get_uint(f);
990,732✔
6044
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
22,071,300✔
6045
            op->func = ident_read(ident_rd_ctx);
525,636✔
6046
         if (OP_HAS_SUBKIND(op->kind))
22,071,300✔
6047
            op->subkind = fbuf_get_uint(f);
177,813✔
6048
         if (OP_HAS_CMP(op->kind))
22,071,300✔
6049
            op->cmp = fbuf_get_uint(f);
578,200✔
6050
         if (OP_HAS_VALUE(op->kind))
22,071,300✔
6051
            op->value = fbuf_get_int(f);
9,539,570✔
6052
         if (OP_HAS_REAL(op->kind))
22,071,300✔
6053
            op->real = read_double(f);
26,847✔
6054
         if (OP_HAS_COMMENT(op->kind))
22,071,300✔
6055
            op->comment = NULL;
1,014,860✔
6056
         if (OP_HAS_DIM(op->kind))
22,071,300✔
6057
            op->dim = fbuf_get_uint(f);
940,021✔
6058
         if (OP_HAS_HOPS(op->kind))
22,071,300✔
6059
            op->hops = fbuf_get_uint(f);
101,428✔
6060
         if (OP_HAS_FIELD(op->kind))
22,071,300✔
6061
            op->field = fbuf_get_uint(f);
13,419✔
6062
         if (OP_HAS_TAG(op->kind))
22,071,300✔
6063
            op->tag = fbuf_get_uint(f);
×
6064
      }
6065
   }
6066

6067
   reg_array_resize(&(unit->regs), fbuf_get_uint(f), 0);
322,373✔
6068
   for (unsigned i = 0; i < unit->regs.count; i++) {
20,187,300✔
6069
      reg_t *r = &(unit->regs.items[i]);
19,865,000✔
6070
      r->type = fbuf_get_uint(f);
19,865,000✔
6071
      r->bounds = fbuf_get_uint(f);
19,865,000✔
6072
   }
6073

6074
   vtype_array_resize(&(unit->types), fbuf_get_uint(f), 0);
322,373✔
6075
   for (unsigned i = 0; i < unit->types.count; i++) {
7,238,870✔
6076
      vtype_t *t = &(unit->types.items[i]);
6,916,500✔
6077
      switch ((t->kind = fbuf_get_uint(f))) {
6,916,500✔
6078
      case VCODE_TYPE_INT:
5,542,230✔
6079
      case VCODE_TYPE_OFFSET:
6080
         t->repr = fbuf_get_int(f);
5,542,230✔
6081
         t->low = fbuf_get_int(f);
5,542,230✔
6082
         t->high = fbuf_get_int(f);
5,542,230✔
6083
         break;
5,542,230✔
6084

6085
      case VCODE_TYPE_REAL:
70,947✔
6086
         t->rlow = read_double(f);
70,947✔
6087
         t->rhigh = read_double(f);
70,947✔
6088
         break;
70,947✔
6089

6090
      case VCODE_TYPE_CARRAY:
507,008✔
6091
      case VCODE_TYPE_UARRAY:
6092
         t->dims = fbuf_get_uint(f);
507,008✔
6093
         t->size = fbuf_get_uint(f);
507,008✔
6094
         t->elem = fbuf_get_uint(f);
507,008✔
6095
         t->bounds = fbuf_get_uint(f);
507,008✔
6096
         break;
507,008✔
6097

6098
      case VCODE_TYPE_POINTER:
340,643✔
6099
      case VCODE_TYPE_ACCESS:
6100
         t->base = fbuf_get_uint(f);
340,643✔
6101
         break;
340,643✔
6102

6103
      case VCODE_TYPE_FILE:
2,754✔
6104
      case VCODE_TYPE_SIGNAL:
6105
      case VCODE_TYPE_RESOLUTION:
6106
      case VCODE_TYPE_CLOSURE:
6107
         t->base = fbuf_get_uint(f);
2,754✔
6108
         break;
2,754✔
6109

6110
      case VCODE_TYPE_OPAQUE:
6111
      case VCODE_TYPE_DEBUG_LOCUS:
6112
         break;
6113

6114
      case VCODE_TYPE_CONTEXT:
332,993✔
6115
         t->name = ident_read(ident_rd_ctx);
332,993✔
6116
         break;
332,993✔
6117

6118
      case VCODE_TYPE_RECORD:
4,140✔
6119
         {
6120
            t->name = ident_read(ident_rd_ctx);
4,140✔
6121
            vcode_type_array_resize(&(t->fields), fbuf_get_uint(f), 0);
4,140✔
6122
            for (unsigned j = 0; j < t->fields.count; j++)
19,448✔
6123
               t->fields.items[j] = fbuf_get_uint(f);
15,308✔
6124
            break;
6125
         }
6126
      }
6127
   }
6,916,500✔
6128

6129
   var_array_resize(&(unit->vars), fbuf_get_uint(f), 0);
322,373✔
6130
   for (unsigned i = 0; i < unit->vars.count; i++) {
617,977✔
6131
      var_t *v = &(unit->vars.items[i]);
295,604✔
6132
      v->type = fbuf_get_uint(f);
295,604✔
6133
      v->bounds = fbuf_get_uint(f);
295,604✔
6134
      v->name = ident_read(ident_rd_ctx);
295,604✔
6135
      v->flags = fbuf_get_uint(f);
295,604✔
6136
   }
6137

6138
   param_array_resize(&(unit->params), fbuf_get_uint(f), 0);
322,373✔
6139
   for (unsigned i = 0; i < unit->params.count; i++) {
1,173,260✔
6140
      param_t *p = &(unit->params.items[i]);
850,883✔
6141
      p->type = fbuf_get_uint(f);
850,883✔
6142
      p->bounds = fbuf_get_uint(f);
850,883✔
6143
      p->name = ident_read(ident_rd_ctx);
850,883✔
6144
      p->reg = fbuf_get_uint(f);
850,883✔
6145
   }
6146

6147
   vcode_registry_add(unit);
322,373✔
6148

6149
   return unit;
322,373✔
6150
}
6151

6152
vcode_unit_t vcode_read(fbuf_t *f, ident_rd_ctx_t ident_ctx,
4,157✔
6153
                        loc_rd_ctx_t *loc_ctx)
6154
{
6155
   const uint8_t version = read_u8(f);
4,157✔
6156
   if (version != VCODE_VERSION) {
4,157✔
6157
      diag_t *d = diag_new(DIAG_FATAL, NULL);
×
6158
      diag_printf(d, "%s was created with vcode format version %d "
×
6159
                  "(expected %d)", fbuf_file_name(f), version, VCODE_VERSION);
6160
      diag_hint(d, NULL, "this file was most likely created with an earlier "
×
6161
                "version of " PACKAGE_NAME " and should be reanalysed");
6162
      diag_emit(d);
×
6163
      fatal_exit(EXIT_FAILURE);
×
6164
   }
6165

6166
   vcode_unit_t vu, root = NULL;
6167
   while ((vu = vcode_read_unit(f, ident_ctx, loc_ctx))) {
326,530✔
6168
      if (root == NULL)
322,373✔
6169
         root = vu;
4,157✔
6170
   }
6171

6172
   return root;
4,157✔
6173
}
6174

6175
#if VCODE_CHECK_UNIONS
6176
#define OP_USE_COUNT_U0(x)                                              \
6177
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6178
#define OP_USE_COUNT_U1(x)                                              \
6179
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6180
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6181
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6182

6183
__attribute__((constructor))
6184
static void vcode_check_unions(void)
6185
{
6186
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6187
   for (int i = 0; i < 256; i++) {
6188
      assert(OP_USE_COUNT_U0(i) <= 1);
6189
      assert(OP_USE_COUNT_U1(i) <= 1);
6190
   }
6191
}
6192
#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