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

nickg / nvc / 4702079372

pending completion
4702079372

push

github

Nick Gasson
Handle linking against ___chkstk_ms on MinGW as a special case. Issue #671

40757 of 45079 relevant lines covered (90.41%)

969590.09 hits per line

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

92.35
/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,282,940✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
1,320,338✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
113,948✔
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,321,270✔
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);
398,427✔
162
DECLARE_AND_DEFINE_ARRAY(var);
374,498✔
163
DECLARE_AND_DEFINE_ARRAY(reg);
2,001,223✔
164
DECLARE_AND_DEFINE_ARRAY(block);
521,381✔
165
DECLARE_AND_DEFINE_ARRAY(vtype);
3,260,813✔
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,848✔
222
{
223
   int64_t result;
56,848✔
224
   if (__builtin_add_overflow(a, b, &result))
56,848✔
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,574✔
231
{
232
   int64_t result;
70,574✔
233
   if (__builtin_sub_overflow(a, b, &result))
70,574✔
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,452✔
240
{
241
   int64_t result;
22,452✔
242
   if (__builtin_mul_overflow(a, b, &result))
22,452✔
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,679,420✔
249
{
250
   assert(active_unit != NULL);
1,679,420✔
251

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

258
   return reg;
1,679,420✔
259
}
260

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

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

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

277
   block_t *block = vcode_block_data();
2,083,390✔
278

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

285
   return op;
2,083,390✔
286
}
287

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

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

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

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

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

317
   return NULL;
318
}
319

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

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

333
   int depth = MASK_CONTEXT(type);
69,348,600✔
334
   assert(depth <= unit->depth);
69,348,600✔
335
   while (depth != unit->depth)
70,248,300✔
336
      unit = unit->context;
899,639✔
337

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

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

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

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

357
   switch (defn->kind) {
32,121✔
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,452✔
374
      vcode_var_data(defn->address)->flags |= VAR_HEAP;
3,452✔
375
      active_unit->flags |= UNIT_ESCAPING_TLAB;
3,452✔
376
      break;
3,452✔
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)
131,947✔
502
{
503
   state->unit  = active_unit;
131,947✔
504
   state->block = active_block;
131,947✔
505
}
131,947✔
506

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

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

517
   if (unit == active_unit)
14,965✔
518
      vcode_close();
14,711✔
519

520
   while (unit->children)
14,997✔
521
      vcode_unit_unref(unit->children);
32✔
522

523
   if (unit->context != NULL) {
14,965✔
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)
14,965✔
532
      hash_delete(registry, unit->name);
36✔
533

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

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

549
   for (unsigned i = 0; i < unit->types.count; i++) {
83,835✔
550
      vtype_t *vt = &(unit->types.items[i]);
68,870✔
551
      if (vt->kind == VCODE_TYPE_RECORD)
68,870✔
552
         free(vt->fields.items);
98✔
553
   }
554
   free(unit->types.items);
14,965✔
555

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

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

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

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

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

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

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

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

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

601
   vtype_t *bounds = vcode_type_data(r->bounds);
960,432✔
602

603
   VCODE_ASSERT(
960,432✔
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) {
960,432✔
608
      if (value) *value = bounds->low;
482,334✔
609
      return true;
482,334✔
610
   }
611
   else
612
      return false;
613
}
614

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

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

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

626
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
441,087✔
627
         block_t *b = &(active_unit->blocks.items[i]);
352,697✔
628

629
         for (int j = b->ops.count - 1; j >= 0; j--) {
4,202,990✔
630
            op_t *o = &(b->ops.items[j]);
3,850,290✔
631

632
            switch (o->kind) {
3,850,290✔
633
            case VCODE_OP_FCALL:
62,701✔
634
               if (o->result == VCODE_INVALID_REG)
62,701✔
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_ADD:
644
            case VCODE_OP_ARRAY_REF:
645
            case VCODE_OP_SUB:
646
            case VCODE_OP_MUL:
647
            case VCODE_OP_CMP:
648
            case VCODE_OP_INDEX:
649
            case VCODE_OP_WRAP:
650
            case VCODE_OP_EXP:
651
            case VCODE_OP_UNDEFINED:
652
            case VCODE_OP_UARRAY_LEN:
653
            case VCODE_OP_UARRAY_DIR:
654
            case VCODE_OP_UARRAY_LEFT:
655
            case VCODE_OP_UARRAY_RIGHT:
656
            case VCODE_OP_UNWRAP:
657
            case VCODE_OP_NULL:
658
            case VCODE_OP_ADDRESS_OF:
659
            case VCODE_OP_RANGE_NULL:
660
            case VCODE_OP_RANGE_LENGTH:
661
            case VCODE_OP_DEBUG_LOCUS:
662
            case VCODE_OP_SELECT:
663
            case VCODE_OP_CAST:
664
            case VCODE_OP_RESOLVED:
665
            case VCODE_OP_TRAP_ADD:
666
            case VCODE_OP_TRAP_SUB:
667
            case VCODE_OP_TRAP_MUL:
668
            case VCODE_OP_TRAP_EXP:
669
               if (uses[o->result] == -1) {
2,348,360✔
670
                  vcode_dump_with_mark(j, NULL, NULL);
×
671
                  fatal("defintion of r%d does not dominate all uses",
×
672
                        o->result);
673
               }
674
               else if (uses[o->result] == 0) {
2,348,360✔
675
                  if (false DEBUG_ONLY(|| o->kind != VCODE_OP_CONST)) {
320,282✔
676
                     o->comment = xasprintf("Dead %s definition of r%d",
159,885✔
677
                                            vcode_op_string(o->kind),
678
                                            o->result);
679
                     o->kind = VCODE_OP_COMMENT;
159,885✔
680
                  }
681
                  else
682
                     o->kind = (vcode_op_t)-1;
160,397✔
683
                  vcode_reg_array_resize(&(o->args), 0, VCODE_INVALID_REG);
320,282✔
684
                  pruned++;
320,282✔
685
               }
686
               uses[o->result] = -1;
2,348,360✔
687
               break;
2,348,360✔
688

689
            default:
690
               break;
691
            }
692

693
            for (int k = 0; k < o->args.count; k++) {
9,279,890✔
694
               if (o->args.items[k] != VCODE_INVALID_REG)
5,429,600✔
695
                  uses[o->args.items[k]]++;
5,391,000✔
696
            }
697
         }
698
      }
699
   } while (pruned > 0);
88,390✔
700

701
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
254,010✔
702
      block_t *b = &(active_unit->blocks.items[i]);
199,578✔
703
      op_t *dst = &(b->ops.items[0]);
199,578✔
704
      size_t copied = 0;
199,578✔
705
      for (int j = 0; j < b->ops.count; j++) {
2,282,970✔
706
         const op_t *src = &(b->ops.items[j]);
2,083,390✔
707
         if (src->kind != (vcode_op_t)-1) {
2,083,390✔
708
            if (src != dst) {
1,922,990✔
709
               assert(dst < src);
727,897✔
710
               *dst = *src;
727,897✔
711
            }
712
            dst++;
1,922,990✔
713
            copied++;
1,922,990✔
714
         }
715
      }
716

717
      assert(copied <= b->ops.count);
199,578✔
718
      b->ops.count = copied;
199,578✔
719
   }
720
}
54,432✔
721

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

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

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

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

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

755
   return VCODE_INVALID_VAR;
756
}
757

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

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

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

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

778
vcode_op_t vcode_get_op(int op)
2,137,590✔
779
{
780
   return vcode_op_data(op)->kind;
2,137,590✔
781
}
782

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

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

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

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

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

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

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

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

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

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

853
int vcode_count_args(int op)
175,729✔
854
{
855
   return vcode_op_data(op)->args.count;
175,729✔
856
}
857

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

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

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

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

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

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

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

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

905
bool vcode_block_finished(void)
2,190,710✔
906
{
907
   assert(active_unit != NULL);
2,190,710✔
908
   assert(active_block != VCODE_INVALID_BLOCK);
2,190,710✔
909

910
   const block_t *b = &(active_unit->blocks.items[active_block]);
2,190,710✔
911
   if (b->ops.count == 0)
2,190,710✔
912
      return false;
913
   else {
914
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,942,540✔
915
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,942,540✔
916
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,942,530✔
917
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE;
5,813,120✔
918
   }
919
}
920

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

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

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

964
   return printed;
×
965
}
966

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1087
   return col;
×
1088
}
1089

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

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

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

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

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

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

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

1143
   dump_callback = callback;
1144
   dump_arg = arg;
1145

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2236
   active_block = old_block;
2237
}
2238
LCOV_EXCL_STOP
2239

2240
bool vtype_eq(vcode_type_t a, vcode_type_t b)
31,891,400✔
2241
{
2242
   assert(active_unit != NULL);
32,479,300✔
2243

2244
   if (a == b)
32,479,300✔
2245
      return true;
2246
   else {
2247
      const vtype_t *at = vcode_type_data(a);
29,767,200✔
2248
      const vtype_t *bt = vcode_type_data(b);
29,767,200✔
2249

2250
      if (at->kind != bt->kind)
29,767,200✔
2251
         return false;
2252

2253
      switch (at->kind) {
12,635,400✔
2254
      case VCODE_TYPE_INT:
11,210,200✔
2255
         return (at->low == bt->low) && (at->high == bt->high);
20,820,100✔
2256
      case VCODE_TYPE_REAL:
185,788✔
2257
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
342,502✔
2258
      case VCODE_TYPE_CARRAY:
70,083✔
2259
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
81,569✔
2260
      case VCODE_TYPE_UARRAY:
93,859✔
2261
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
117,044✔
2262
      case VCODE_TYPE_POINTER:
514,405✔
2263
      case VCODE_TYPE_ACCESS:
2264
         return vtype_eq(at->pointed, bt->pointed);
514,405✔
2265
      case VCODE_TYPE_OFFSET:
2266
      case VCODE_TYPE_OPAQUE:
2267
      case VCODE_TYPE_DEBUG_LOCUS:
2268
         return true;
2269
      case VCODE_TYPE_RESOLUTION:
73,494✔
2270
      case VCODE_TYPE_CLOSURE:
2271
      case VCODE_TYPE_SIGNAL:
2272
      case VCODE_TYPE_FILE:
2273
         return vtype_eq(at->base, bt->base);
73,494✔
2274
      case VCODE_TYPE_RECORD:
55,653✔
2275
      case VCODE_TYPE_CONTEXT:
2276
         return at->name == bt->name;
55,653✔
2277
      }
2278

2279
      return false;
×
2280
   }
2281
}
2282

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

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

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

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

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

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

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

2320
   return false;
2321
}
2322

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

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

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

2341
   return type;
2342
}
2343

2344
vcode_type_t vtype_int(int64_t low, int64_t high)
1,976,290✔
2345
{
2346
   assert(active_unit != NULL);
1,976,290✔
2347

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

2353
   switch (bits_for_range(low, high)) {
1,976,290✔
2354
   case 64:
89,560✔
2355
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
89,560✔
2356
      break;
89,560✔
2357
   case 32:
550,069✔
2358
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
550,069✔
2359
      break;
550,069✔
2360
   case 16:
2,631✔
2361
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
2,631✔
2362
      break;
2,631✔
2363
   case 8:
488,432✔
2364
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
488,432✔
2365
      break;
488,432✔
2366
   case 1:
845,600✔
2367
      n->repr = VCODE_REPR_U1;
845,600✔
2368
      break;
845,600✔
2369
   default:
×
2370
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
×
2371
   }
2372

2373
   return vtype_new(n);
1,976,290✔
2374
}
2375

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

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

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

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

2396
   return vtype_new(n);
32,678✔
2397
}
2398

2399
vcode_type_t vtype_find_named_record(ident_t name)
66,837✔
2400
{
2401
   assert(active_unit != NULL);
66,837✔
2402

2403
   for (int i = 0; i < active_unit->types.count; i++) {
519,911✔
2404
      vtype_t *other = &(active_unit->types.items[i]);
497,267✔
2405
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
497,267✔
2406
         return MAKE_HANDLE(active_unit->depth, i);
44,193✔
2407
   }
2408

2409
   return VCODE_INVALID_TYPE;
2410
}
2411

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

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

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

2433
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
22,644✔
2434
   for (int i = 0; i < nfields; i++)
66,226✔
2435
      vcode_type_array_add(&(data->fields), field_types[i]);
43,582✔
2436

2437
   return handle;
22,644✔
2438
}
2439

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

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

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

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

2457
   return vtype_new(n);
99,273✔
2458
}
2459

2460
vcode_type_t vtype_pointer(vcode_type_t to)
200,922✔
2461
{
2462
   assert(active_unit != NULL);
200,922✔
2463

2464
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
200,922✔
2465
   n->kind    = VCODE_TYPE_POINTER;
200,922✔
2466
   n->pointed = to;
200,922✔
2467

2468
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
200,922✔
2469
                "cannot get pointer to carray type");
2470

2471
   return vtype_new(n);
200,922✔
2472
}
2473

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

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

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

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

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

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

2495
   return vtype_new(n);
29,432✔
2496
}
2497

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

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

2506
   return vtype_new(n);
477✔
2507
}
2508

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

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

2517
   return vtype_new(n);
594✔
2518
}
2519

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

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

2528
   return vtype_new(n);
56,399✔
2529
}
2530

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

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

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

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

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

2552
   return vtype_new(n);
300,495✔
2553
}
2554

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

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

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

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

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

2575
vcode_type_t vtype_debug_locus(void)
185,968✔
2576
{
2577
   assert(active_unit != NULL);
185,968✔
2578

2579
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
185,968✔
2580
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
185,968✔
2581

2582
   return vtype_new(n);
185,968✔
2583
}
2584

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

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

2594
   return vtype_new(n);
39,187✔
2595
}
2596

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2695
bool vtype_is_scalar(vcode_type_t type)
319,815✔
2696
{
2697
   const vtype_kind_t kind = vtype_kind(type);
319,815✔
2698
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
319,815✔
2699
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
99,820✔
2700
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
65,462✔
2701
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
62,414✔
2702
      || kind == VCODE_TYPE_CONTEXT;
320,235✔
2703
}
2704

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

2711
bool vtype_is_signal(vcode_type_t type)
192,714✔
2712
{
2713
   vtype_t *vt = vcode_type_data(type);
343,817✔
2714
   switch (vt->kind) {
343,817✔
2715
   case VCODE_TYPE_SIGNAL:
2716
      return true;
2717
   case VCODE_TYPE_POINTER:
59,935✔
2718
      return vtype_is_signal(vt->pointed);
59,935✔
2719
   case VCODE_TYPE_RECORD:
2720
      for (int i = 0; i < vt->fields.count; i++) {
47,010✔
2721
         if (vtype_is_signal(vt->fields.items[i]))
38,202✔
2722
            return true;
2723
      }
2724
      return false;
2725
   case VCODE_TYPE_UARRAY:
91,168✔
2726
   case VCODE_TYPE_CARRAY:
2727
      return vtype_is_signal(vt->elem);
91,168✔
2728
   default:
161,159✔
2729
      return false;
161,159✔
2730
   }
2731
}
2732

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

2745
bool vtype_repr_signed(vtype_repr_t repr)
41,934✔
2746
{
2747
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
41,934✔
2748
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
41,934✔
2749
}
2750

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

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

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

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

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

2804
   return active_unit->params.count;
22,991✔
2805
}
2806

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

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

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

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

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

2833
   vcode_block_t bnum = active_unit->blocks.count;
199,578✔
2834

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

2838
   if (active_block != VCODE_INVALID_BLOCK)
199,578✔
2839
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
145,146✔
2840
   else
2841
      bptr->last_loc = LOC_INVALID;
54,432✔
2842

2843
   return bnum;
199,578✔
2844
}
2845

2846
void vcode_select_unit(vcode_unit_t unit)
414,135✔
2847
{
2848
   active_unit  = unit;
414,135✔
2849
   active_block = VCODE_INVALID_BLOCK;
414,135✔
2850
}
414,135✔
2851

2852
void vcode_select_block(vcode_block_t block)
463,334✔
2853
{
2854
   assert(active_unit != NULL);
463,334✔
2855
   active_block = block;
463,334✔
2856
}
463,334✔
2857

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

2865
const loc_t *vcode_last_loc(void)
831,148✔
2866
{
2867
   return &(vcode_block_data()->last_loc);
831,148✔
2868
}
2869

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

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

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

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

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

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

2905
   active_unit->result = type;
39,125✔
2906
}
39,125✔
2907

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

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

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

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

2935
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
69,373✔
2936
{
2937
   int hops = 0;
69,373✔
2938
   for (; (unit = unit->context); hops++)
130,003✔
2939
      ;
60,630✔
2940
   return hops;
69,373✔
2941
}
2942

2943
static void vcode_registry_add(vcode_unit_t vu)
361,294✔
2944
{
2945
   if (registry == NULL)
361,294✔
2946
      registry = hash_new(512);
3,209✔
2947

2948
   hash_put(registry, vu->name, vu);
361,294✔
2949
}
361,294✔
2950

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

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

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

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

2984
   object_locus(obj, &vu->module, &vu->offset);
25,622✔
2985

2986
   vcode_add_child(context, vu);
25,622✔
2987

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

2992
   vcode_registry_add(vu);
25,622✔
2993

2994
   return vu;
25,622✔
2995
}
2996

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

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

3008
   vcode_add_child(context, vu);
702✔
3009

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

3014
   vcode_registry_add(vu);
702✔
3015

3016
   return vu;
702✔
3017
}
3018

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

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

3030
   object_locus(obj, &vu->module, &vu->offset);
6,328✔
3031

3032
   vcode_add_child(context, vu);
6,328✔
3033

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

3038
   vcode_registry_add(vu);
6,328✔
3039

3040
   return vu;
6,328✔
3041
}
3042

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

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

3054
   object_locus(obj, &vu->module, &vu->offset);
5,961✔
3055

3056
   if (context != NULL)
5,961✔
3057
      vcode_add_child(context, vu);
3,494✔
3058

3059
   vcode_select_unit(vu);
5,961✔
3060
   vcode_select_block(emit_block());
5,961✔
3061
   emit_debug_info(&(obj->loc));
5,961✔
3062

3063
   vcode_registry_add(vu);
5,961✔
3064

3065
   return vu;
5,961✔
3066
}
3067

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

3077
   object_locus(obj, &vu->module, &vu->offset);
791✔
3078

3079
   if (context != NULL)
791✔
3080
      vcode_add_child(context, vu);
92✔
3081

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

3086
   vcode_registry_add(vu);
791✔
3087

3088
   return vu;
791✔
3089
}
3090

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

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

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

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

3109
   vcode_registry_add(vu);
81✔
3110

3111
   return vu;
81✔
3112
}
3113

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

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

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

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

3132
   vcode_registry_add(vu);
6✔
3133

3134
   return vu;
6✔
3135
}
3136

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

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

3149
   if (context != NULL)
14,941✔
3150
      vcode_add_child(context, vu);
105✔
3151

3152
   vcode_select_unit(vu);
14,941✔
3153
   vcode_select_block(emit_block());
14,941✔
3154

3155
   if (name != NULL)
14,941✔
3156
      vcode_registry_add(vu);
×
3157

3158
   return vu;
14,941✔
3159
}
3160

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

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

3178
   if (hint_left != VCODE_INVALID_REG) {
9,948✔
3179
      vcode_add_arg(op, hint_left);
4,032✔
3180
      vcode_add_arg(op, hint_right);
4,032✔
3181

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

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

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

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

3216
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
91,783✔
3217
{
3218
   if (lhs == rhs) {
91,783✔
3219
      if (cmp == VCODE_CMP_EQ)
8,524✔
3220
         return emit_const(vtype_bool(), 1);
8,292✔
3221
      else if (cmp == VCODE_CMP_NEQ)
232✔
3222
         return emit_const(vtype_bool(), 0);
2✔
3223
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
230✔
3224
         return emit_const(vtype_bool(), 1);
×
3225
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
230✔
3226
         return emit_const(vtype_bool(), 0);
230✔
3227
   }
3228

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

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

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

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

3265
   return op->result;
3266
}
3267

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

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

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

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

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

3294
      return o->result;
33,659✔
3295
   }
3296
}
3297

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

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

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

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

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

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

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

3334
   return op->result;
9,536✔
3335
}
3336

3337
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
1,124,840✔
3338
{
3339
   // Reuse any previous constant in this block with the same type and value
3340
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
28,156,500✔
3341
      if (other->kind == VCODE_OP_CONST && other->value == value
7,725,420✔
3342
          && vtype_eq(type, other->type))
904,207✔
3343
         return other->result;
606,839✔
3344
   }
3345

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

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

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

3358
   return op->result;
518,003✔
3359
}
3360

3361
vcode_reg_t emit_const_real(vcode_type_t type, double value)
13,840✔
3362
{
3363
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
370,779✔
3364
      if (other->real == value && other->type == type)
145,721✔
3365
         return other->result;
4,061✔
3366
   }
3367

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

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

3376
   return op->result;
9,779✔
3377
}
3378

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

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

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

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

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

3402
   for (int i = 0; i < num; i++)
1,142,030✔
3403
      vcode_add_arg(op, values[i]);
1,125,370✔
3404

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

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

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

3420
   return op->result;
16,662✔
3421
}
3422

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

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

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

3441
   op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
80✔
3442

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

3446
   return op->result;
80✔
3447
}
3448

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

3458
         if (same_regs && vtype_eq(vcode_reg_type(other->result), type))
917✔
3459
            return other->result;
384✔
3460
      }
3461
   }
3462

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

3467
   for (int i = 0; i < num; i++)
7,457✔
3468
      vcode_add_arg(op, values[i]);
5,677✔
3469

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

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

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

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

3492
   return op->result;
1,780✔
3493
}
3494

3495
vcode_reg_t emit_address_of(vcode_reg_t value)
18,821✔
3496
{
3497
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
635,573✔
3498
      if (other->args.items[0] == value)
25,563✔
3499
         return other->result;
1,317✔
3500
   }
3501

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

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

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

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

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

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

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

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

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

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

3555
   return var;
52,695✔
3556
}
3557

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

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

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

3572
   return p->reg;
76,624✔
3573
}
3574

3575
vcode_reg_t emit_load(vcode_var_t var)
89,337✔
3576
{
3577
   // Try scanning backwards through the block for another load or store to
3578
   // this variable
3579
   vcode_reg_t fold = VCODE_INVALID_REG;
89,337✔
3580
   bool aliased = false;
89,337✔
3581
   VCODE_FOR_EACH_OP(other) {
1,008,660✔
3582
      if (fold == VCODE_INVALID_REG) {
934,338✔
3583
         if (other->kind == VCODE_OP_LOAD && other->address == var)
630,772✔
3584
            fold = other->result;
17,221✔
3585
         else if (other->kind == VCODE_OP_STORE && other->address == var)
613,551✔
3586
            fold = other->args.items[0];
13,551✔
3587
      }
3588

3589
      if (other->kind == VCODE_OP_INDEX && other->address == var)
934,338✔
3590
         aliased = true;
3591
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
934,275✔
3592
         break;   // Nested call captures variables
3593
      else if (other->kind == VCODE_OP_FILE_READ)
919,321✔
3594
         break;   // May write to variable
3595
   }
3596

3597
   var_t *v = vcode_var_data(var);
89,337✔
3598

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

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

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

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

3611
   return op->result;
58,598✔
3612
}
3613

3614
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
104,856✔
3615
{
3616
   VCODE_FOR_EACH_OP(other) {
1,056,220✔
3617
      if (other->kind == VCODE_OP_LOAD_INDIRECT
996,157✔
3618
          && other->args.items[0] == reg) {
133,150✔
3619
         return other->result;
5,615✔
3620
      }
3621
      else if (other->kind == VCODE_OP_FCALL
990,542✔
3622
               || other->kind == VCODE_OP_PCALL
990,542✔
3623
               || other->kind == VCODE_OP_STORE
986,268✔
3624
               || other->kind == VCODE_OP_STORE_INDIRECT
963,590✔
3625
               || other->kind == VCODE_OP_MEMSET
955,703✔
3626
               || other->kind == VCODE_OP_COPY
955,409✔
3627
               || other->kind == VCODE_OP_FILE_READ)
951,381✔
3628
         break;   // May write to this pointer
3629
   }
3630

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

3634
   vcode_type_t rtype = vcode_reg_type(reg);
99,241✔
3635

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

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

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

3644
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
99,241✔
3645

3646
   return op->result;
99,241✔
3647
}
3648

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

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

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

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

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

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

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

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

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

3709
   op->result = vcode_add_reg(vcode_reg_type(lhs));
71,404✔
3710

3711
   vcode_type_t lhs_type = vcode_reg_type(lhs);
71,404✔
3712
   vcode_type_t rhs_type = vcode_reg_type(rhs);
71,404✔
3713

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

3717
   return op->result;
3718
}
3719

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

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

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

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

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

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

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

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

3768
      vbounds = vtype_int(min, max);
5,613✔
3769
   }
3770

3771
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
6,182✔
3772

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

3776
   return reg;
3777
}
3778

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

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

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

3791
   return result;
2,074✔
3792
}
3793

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

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

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

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

3817
   return reg;
3818
}
3819

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

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

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

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

3837
   return result;
1,244✔
3838
}
3839

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

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

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

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

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

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

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

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

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

3881
   return reg;
3882
}
3883

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

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

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

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

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

3914
      vbounds = vtype_int(rbl, rbh);
28,424✔
3915
   }
3916

3917
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
28,669✔
3918

3919
   if (vbounds != VCODE_INVALID_TYPE)
28,669✔
3920
      vcode_reg_data(reg)->bounds = vbounds;
28,424✔
3921

3922
   return reg;
3923
}
3924

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

3930
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
5,997✔
3931
{
3932
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
5,997✔
3933

3934
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
5,997✔
3935
                "trapping add may only be used with integer types");
3936

3937
   return result;
5,997✔
3938
}
3939

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

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

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

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

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

3970
      vbounds = vtype_int(rbl, rbh);
35,287✔
3971
   }
3972

3973
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
35,563✔
3974

3975
   if (vbounds != VCODE_INVALID_TYPE)
35,563✔
3976
      vcode_reg_data(reg)->bounds = vbounds;
35,287✔
3977

3978
   return reg;
3979
}
3980

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

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

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

3993
   return result;
18,925✔
3994
}
3995

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

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

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

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

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

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

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

4047
   vcode_calculate_var_index_type(op, vcode_var_data(var));
13,091✔
4048

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

4053
   return op->result;
13,091✔
4054
}
4055

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

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

4064
   const bool integral =
205,058✔
4065
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
102,529✔
4066
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
102,529✔
4067

4068
   int64_t value;
102,529✔
4069
   if (integral && vcode_reg_const(reg, &value))
102,529✔
4070
      return emit_const(type, value);
14,092✔
4071

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

4078
   op_t *op = vcode_add_op(VCODE_OP_CAST);
54,917✔
4079
   vcode_add_arg(op, reg);
54,917✔
4080
   op->type   = type;
54,917✔
4081
   op->result = vcode_add_reg(type);
54,917✔
4082

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

4093
   if (from == VCODE_TYPE_INT && bounds == VCODE_INVALID_TYPE) {
54,917✔
4094
      reg_t *rr = vcode_reg_data(op->result);
10,618✔
4095
      rr->bounds = vcode_reg_bounds(reg);
10,618✔
4096
   }
4097
   else if (to == VCODE_TYPE_INT && bounds != VCODE_INVALID_TYPE) {
44,299✔
4098
      reg_t *rr = vcode_reg_data(op->result);
35,633✔
4099
      rr->bounds = bounds;
35,633✔
4100
   }
4101

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4299
   return op->result;
17,687✔
4300
}
4301

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

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

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

4356
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
11,280✔
4357

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

4362
   return result;
4363
}
4364

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

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

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

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

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

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

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

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

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

4407
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
37,253✔
4408
{
4409
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,085,230✔
4410
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
82,233✔
4411
         bool match = true;
4412
         for (int i = 0; match && i < ndims; i++) {
9,847✔
4413
            match = other->args.items[i*3 + 1] == dims[i].left
4,960✔
4414
               && other->args.items[i*3 + 2] == dims[i].right
4,233✔
4415
               && other->args.items[i*3 + 3] == dims[i].dir;
9,129✔
4416
         }
4417
         if (match)
4,887✔
4418
            return other->result;
4,096✔
4419
      }
4420
   }
4421

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

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

4435
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
66,314✔
4436
      ? vtype_pointed(ptr_type) : ptr_type;
33,157✔
4437

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

4441
   return op->result;
33,157✔
4442
}
4443

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

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

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

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

4469
   if (rtype == VCODE_INVALID_TYPE)
63,740✔
4470
      rtype = vtype_offset();
41,399✔
4471

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

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

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

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

4493
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
57,835✔
4494
{
4495
   VCODE_FOR_EACH_OP(other) {
652,283✔
4496
      if (other->kind == VCODE_OP_UARRAY_LEN) {
615,704✔
4497
         if (other->args.items[0] == array && other->dim == dim)
47,954✔
4498
            return other->result;
14,274✔
4499
      }
4500
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
567,750✔
4501
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
6,982✔
4502
                      "array dimension %d out of bounds", dim);
4503

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

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

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

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

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

4525
vcode_reg_t emit_unwrap(vcode_reg_t array)
47,941✔
4526
{
4527
   VCODE_FOR_EACH_OP(other) {
870,968✔
4528
      if (other->kind == VCODE_OP_WRAP && other->result == array)
830,667✔
4529
         return other->args.items[0];
4,657✔
4530
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
826,010✔
4531
         return other->result;
2,983✔
4532
   }
4533

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

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

4541
   vcode_type_t elem = vt->elem;
40,301✔
4542

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

4546
   op->result = vcode_add_reg(rtype);
40,301✔
4547

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

4551
   return op->result;
40,301✔
4552
}
4553

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

4564
   int64_t dir_const;
16,815✔
4565
   if (vcode_reg_const(dir, &dir_const)) {
16,815✔
4566
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
11,982✔
4567
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
11,982✔
4568

4569
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
11,982✔
4570
         return emit_const(vtype_bool(), 1);
38✔
4571
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
11,944✔
4572
         return emit_const(vtype_bool(), 0);
3,938✔
4573
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
8,006✔
4574
         return emit_const(vtype_bool(), 1);
46✔
4575
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
7,960✔
4576
         return emit_const(vtype_bool(), 0);
1,797✔
4577
      else if (dir_const == RANGE_TO)
6,163✔
4578
         return emit_cmp(VCODE_CMP_GT, left, right);
1,288✔
4579
      else
4580
         return emit_cmp(VCODE_CMP_GT, right, left);
4,875✔
4581
   }
4582

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

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

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

4596
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
24,997✔
4597
                              vcode_reg_t dir)
4598
{
4599
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_LENGTH) {
446,719✔
4600
      if (other->args.items[0] == left
12,439✔
4601
          && other->args.items[1] == right
9,920✔
4602
          && other->args.items[2] == dir)
9,176✔
4603
         return other->result;
9,170✔
4604
   }
4605

4606
   int64_t lconst, rconst, dconst;
15,827✔
4607
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
15,827✔
4608
       && vcode_reg_const(right, &rconst)) {
6,801✔
4609

4610
      int64_t diff;
4,966✔
4611
      if (dconst == RANGE_TO)
4,966✔
4612
         diff = rconst - lconst;
4,653✔
4613
      else
4614
         diff = lconst - rconst;
313✔
4615

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

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

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

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

4632
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
41,446✔
4633
{
4634
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
645,813✔
4635
      if (other->hops == hops && other->address == var)
69,069✔
4636
         return other->result;
6,766✔
4637
   }
4638

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

4643
   VCODE_ASSERT(hops > 0, "invalid hop count");
34,680✔
4644

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

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

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

4655
   return op->result;
34,680✔
4656
}
4657

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4818
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
15,034✔
4819
{
4820
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
19,858✔
4821
      if (other->func == name && other->subkind == VCODE_CC_VHDL)
9,969✔
4822
         return other->result;
5,586✔
4823
   }
4824

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4922
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
56,237✔
4923
{
4924
   // Try scanning backwards through the block for another record ref
4925
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
2,449,200✔
4926
      if (other->args.items[0] == record && other->field == field)
557,946✔
4927
         return other->result;
2,318✔
4928
   }
4929

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

4934
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
53,919✔
4935

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

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

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

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

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

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

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

4962
   if (is_signal)
53,919✔
4963
      result_type = vtype_signal(result_type);
×
4964

4965
   op->result = vcode_add_reg(vtype_pointer(result_type));
53,919✔
4966

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

4970
   return op->result;
53,919✔
4971
}
4972

4973
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
56,375✔
4974
{
4975
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
1,119,470✔
4976
      if (other->args.items[0] == array && other->args.items[1] == offset)
58,607✔
4977
         return other->result;
1,203✔
4978
   }
4979

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

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

4992
   op->result = vcode_add_reg(rtype);
55,172✔
4993

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

4997
   return op->result;
55,172✔
4998
}
4999

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

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

5015
   vcode_type_t dtype = vcode_reg_type(dest);
17,822✔
5016
   vcode_type_t stype = vcode_reg_type(src);
17,822✔
5017

5018
   vtype_kind_t dkind = vtype_kind(dtype);
17,822✔
5019
   vtype_kind_t skind = vtype_kind(stype);
17,822✔
5020

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5226
vcode_reg_t emit_null(vcode_type_t type)
2,673✔
5227
{
5228
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
101,897✔
5229
      if (vtype_eq(vcode_reg_type(other->result), type))
1,863✔
5230
         return other->result;
977✔
5231
   }
5232

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

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

5241
   return op->result;
5242
}
5243

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5318
   return op->result;
5319
}
5320

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

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

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

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

5339
   vcode_type_t rtype = vtype_base(stype);
16,005✔
5340

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

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

5348
   op->result = vcode_add_reg(vtype_pointer(rtype));
16,005✔
5349

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

5353
   return op->result;
16,005✔
5354
}
5355

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

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

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

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

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

5382
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
36✔
5383
{
5384
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
36✔
5385
   vcode_add_arg(op, signal);
36✔
5386
   if (len != VCODE_INVALID_REG)
36✔
5387
      vcode_add_arg(op, len);
27✔
5388

5389
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5390
                "signal argument to last active must have signal type");
5391
   VCODE_ASSERT(len == VCODE_INVALID_REG
36✔
5392
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5393
                "length argument to last active must have offset type");
5394

5395
   return (op->result = vcode_add_reg(vtype_time()));
36✔
5396
}
5397

5398
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
2,567✔
5399
{
5400
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
2,567✔
5401
   vcode_add_arg(op, signal);
2,567✔
5402
   vcode_add_arg(op, locus);
2,567✔
5403

5404
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
2,567✔
5405
                "signal argument must have signal type");
5406
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,567✔
5407
                "locus argument must have debug locus type");
5408
}
2,567✔
5409

5410
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
30✔
5411
{
5412
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
30✔
5413
   vcode_add_arg(op, signal);
30✔
5414
   vcode_add_arg(op, len);
30✔
5415

5416
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
30✔
5417
                "signal argument to last active must have signal type");
5418
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
30✔
5419
                "length argument to last active must have offset type");
5420

5421
   return (op->result = vcode_add_reg(vtype_bool()));
30✔
5422
}
5423

5424
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
24✔
5425
{
5426
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
24✔
5427
   vcode_add_arg(op, signal);
24✔
5428
   if (len != VCODE_INVALID_REG)
24✔
5429
      vcode_add_arg(op, len);
3✔
5430

5431
   vcode_type_t signal_type = vcode_reg_type(signal);
24✔
5432

5433
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
24✔
5434
                "signal argument to last active must have signal type");
5435
   VCODE_ASSERT(len == VCODE_INVALID_REG
24✔
5436
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5437
                "length argument to last active must have offset type");
5438

5439
   vcode_type_t base_type = vtype_base(signal_type);
24✔
5440
   op->result = vcode_add_reg(vtype_pointer(base_type));
24✔
5441

5442
   reg_t *rr = vcode_reg_data(op->result);
24✔
5443
   rr->bounds = base_type;
24✔
5444

5445
   return op->result;
24✔
5446
}
5447

5448
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
19,010✔
5449
                       vcode_reg_t dim)
5450
{
5451
   if (rlen == llen)
19,010✔
5452
      return;
5453

5454
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
164,817✔
5455
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
2,815✔
5456
         return;
5457
   }
5458

5459
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
7,119✔
5460
   vcode_add_arg(op, llen);
7,119✔
5461
   vcode_add_arg(op, rlen);
7,119✔
5462
   vcode_add_arg(op, locus);
7,119✔
5463
   if (dim != VCODE_INVALID_REG)
7,119✔
5464
      vcode_add_arg(op, dim);
50✔
5465

5466
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
7,119✔
5467
                "locus argument to length check must be a debug locus");
5468
}
5469

5470
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
1,244✔
5471
{
5472
   int64_t cval;
1,244✔
5473
   if (vcode_reg_const(exp, &cval) && cval >= 0)
1,244✔
5474
      return;
757✔
5475

5476
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
2,642✔
5477
      if (other->args.items[0] == exp)
×
5478
         return;
5479
   }
5480

5481
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
487✔
5482
   vcode_add_arg(op, exp);
487✔
5483
   vcode_add_arg(op, locus);
487✔
5484

5485
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
487✔
5486
                "exp argument to exponent check must be a integer");
5487
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
487✔
5488
                "locus argument to exponent check must be a debug locus");
5489
}
5490

5491
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
835✔
5492
{
5493
   int64_t cval;
835✔
5494
   if (vcode_reg_const(denom, &cval) && cval != 0)
835✔
5495
      return;
728✔
5496

5497
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
1,394✔
5498
      if (other->args.items[0] == denom)
32✔
5499
         return;
5500
   }
5501

5502
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
107✔
5503
   vcode_add_arg(op, denom);
107✔
5504
   vcode_add_arg(op, locus);
107✔
5505

5506
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
107✔
5507
                "denom argument to zero check must be a integer");
5508
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
107✔
5509
                "locus argument to zero check must be a debug locus");
5510
}
5511

5512
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
95,796✔
5513
                              vcode_reg_t left, vcode_reg_t right,
5514
                              vcode_reg_t dir, vcode_reg_t locus,
5515
                              vcode_reg_t hint)
5516
{
5517
   if (reg == left || reg == right) {
95,796✔
5518
      emit_comment("Elided trivial bounds check for r%d", reg);
21,016✔
5519
      return;
103,252✔
5520
   }
5521

5522
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,741,410✔
5523
      if (other->args.items[0] == reg && other->args.items[1] == left
9,045✔
5524
          && other->args.items[2] == right && other->args.items[3] == dir)
377✔
5525
         return;
5526
   }
5527

5528
   int64_t dconst;
74,405✔
5529
   if (vcode_reg_const(dir, &dconst)) {
74,405✔
5530
      int64_t lconst, rconst;
66,403✔
5531
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
66,403✔
5532
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
61,161✔
5533
            || (dconst == RANGE_DOWNTO && rconst > lconst);
123,869✔
5534

5535
         if (is_null) {
62,708✔
5536
            emit_comment("Elided bounds check for null range");
×
5537
            return;
60,845✔
5538
         }
5539

5540
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
62,708✔
5541

5542
         const bool ok_static =
125,416✔
5543
            (dconst == RANGE_TO
5544
             && bounds->low >= lconst && bounds->high <= rconst)
61,161✔
5545
            || (dconst == RANGE_DOWNTO
67,605✔
5546
                && bounds->low >= rconst && bounds->high <= lconst);
1,547✔
5547

5548
         if (ok_static) {
62,708✔
5549
            emit_comment("Elided bounds check for r%d", reg);
57,704✔
5550
            return;
57,704✔
5551
         }
5552
      }
5553
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
3,695✔
5554
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
3,419✔
5555
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
3,419✔
5556

5557
         assert(lbounds->kind == VCODE_TYPE_REAL);
3,419✔
5558
         assert(rbounds->kind == VCODE_TYPE_REAL);
3,419✔
5559

5560
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
3,419✔
5561
         assert(bounds->kind == VCODE_TYPE_REAL);
3,419✔
5562

5563
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
3,419✔
5564
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
3,141✔
5565
            // Covers the complete double range so can never overflow
5566
            emit_comment("Elided real bounds check for r%d", reg);
3,141✔
5567
            return;
3,141✔
5568
         }
5569
      }
5570
   }
5571

5572
   op_t *op = vcode_add_op(kind);
13,560✔
5573
   vcode_add_arg(op, reg);
13,560✔
5574
   vcode_add_arg(op, left);
13,560✔
5575
   vcode_add_arg(op, right);
13,560✔
5576
   vcode_add_arg(op, dir);
13,560✔
5577
   vcode_add_arg(op, locus);
13,560✔
5578
   vcode_add_arg(op, hint);
13,560✔
5579

5580
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
13,560✔
5581
                "locus argument to bounds check must be a debug locus");
5582
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
13,560✔
5583
                "hint argument to bounds check must be a debug locus");
5584
}
5585

5586
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
60,963✔
5587
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5588
{
5589
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
60,963✔
5590
}
60,963✔
5591

5592
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
34,833✔
5593
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5594
{
5595
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
34,833✔
5596
}
34,833✔
5597

5598
void emit_push_scope(vcode_reg_t locus, vcode_type_t type)
895✔
5599
{
5600
   op_t *op = vcode_add_op(VCODE_OP_PUSH_SCOPE);
895✔
5601
   vcode_add_arg(op, locus);
895✔
5602
   op->type = type;
895✔
5603

5604
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
895✔
5605
                "locus argument to push scope must be a debug locus");
5606
}
895✔
5607

5608
void emit_pop_scope(void)
895✔
5609
{
5610
   vcode_add_op(VCODE_OP_POP_SCOPE);
895✔
5611
}
895✔
5612

5613
vcode_reg_t emit_debug_locus(ident_t unit, ptrdiff_t offset)
210,981✔
5614
{
5615
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
5,253,130✔
5616
      if (other->ident == unit && other->tag == offset)
845,988✔
5617
         return other->result;
25,255✔
5618
   }
5619

5620
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
185,726✔
5621
   op->ident = unit;
185,726✔
5622
   op->value = offset;
185,726✔
5623

5624
   return (op->result = vcode_add_reg(vtype_debug_locus()));
185,726✔
5625
}
5626

5627
void emit_debug_out(vcode_reg_t reg)
×
5628
{
5629
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
5630
   vcode_add_arg(op, reg);
×
5631
}
×
5632

5633
void emit_cover_stmt(uint32_t tag)
600✔
5634
{
5635
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
600✔
5636
   op->tag = tag;
600✔
5637
}
600✔
5638

5639
void emit_cover_branch(vcode_reg_t test, uint32_t tag, uint32_t flags)
284✔
5640
{
5641
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
284✔
5642
   vcode_add_arg(op, test);
284✔
5643
   op->tag = tag;
284✔
5644
   op->subkind = flags;
284✔
5645
}
284✔
5646

5647
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
269✔
5648
{
5649
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
269✔
5650
   vcode_add_arg(op, signal);
269✔
5651
   op->tag = tag;
269✔
5652
}
269✔
5653

5654
void emit_cover_expr(vcode_reg_t new_mask, uint32_t tag)
303✔
5655
{
5656
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
303✔
5657
   vcode_add_arg(op, new_mask);
303✔
5658
   op->tag = tag;
303✔
5659
}
303✔
5660

5661
void emit_unreachable(vcode_reg_t locus)
104✔
5662
{
5663
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
104✔
5664
   if (locus != VCODE_INVALID_REG)
104✔
5665
      vcode_add_arg(op, locus);
104✔
5666
}
104✔
5667

5668
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
1,272✔
5669
{
5670
   active_unit->flags |= UNIT_UNDEFINED;
1,272✔
5671

5672
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
1,272✔
5673
   op->result = vcode_add_reg(type);
1,272✔
5674
   vcode_reg_data(op->result)->bounds = bounds;
1,272✔
5675

5676
   return op->result;
1,272✔
5677
}
5678

5679
vcode_reg_t emit_strconv(vcode_reg_t ptr, vcode_reg_t len, vcode_reg_t used_ptr,
103✔
5680
                         vcode_type_t type)
5681
{
5682
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_STRCONV) {
339✔
5683
      if (other->args.items[0] == ptr && other->args.items[1] == len
×
5684
          && other->type == type && used_ptr == VCODE_INVALID_REG)
×
5685
         return other->result;
×
5686
   }
5687

5688
   op_t *op = vcode_add_op(VCODE_OP_STRCONV);
103✔
5689
   vcode_add_arg(op, ptr);
103✔
5690
   vcode_add_arg(op, len);
103✔
5691
   if (used_ptr != VCODE_INVALID_REG)
103✔
5692
      vcode_add_arg(op, used_ptr);
30✔
5693
   op->type = type;
103✔
5694

5695
   VCODE_ASSERT(vcode_reg_kind(ptr) == VCODE_TYPE_POINTER,
103✔
5696
                "strconv ptr argument must be pointer");
5697
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
103✔
5698
                "strconv len argument must be offset");
5699
   VCODE_ASSERT(used_ptr == VCODE_INVALID_REG
103✔
5700
                || vcode_reg_kind(used_ptr) == VCODE_TYPE_POINTER,
5701
                "strconv used_ptr argument must be pointer");
5702
   VCODE_ASSERT(vtype_is_scalar(type), "strconv result must be scalar");
103✔
5703

5704
   return (op->result = vcode_add_reg(type));
103✔
5705
}
5706

5707
vcode_reg_t emit_convstr(vcode_reg_t value)
103✔
5708
{
5709
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONVSTR) {
130✔
5710
      if (other->args.items[0] == value)
×
5711
         return other->result;
×
5712
   }
5713

5714
   op_t *op = vcode_add_op(VCODE_OP_CONVSTR);
103✔
5715
   vcode_add_arg(op, value);
103✔
5716

5717
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
103✔
5718
                "convstr value must be scalar");
5719

5720
   vcode_type_t vchar = vtype_char();
103✔
5721
   return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar)));
103✔
5722
}
5723

5724
vcode_reg_t emit_canon_value(vcode_reg_t ptr, vcode_reg_t len)
283✔
5725
{
5726
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CANON_VALUE) {
999✔
5727
      if (other->args.items[0] == ptr && other->args.items[1] == len)
×
5728
         return other->result;
×
5729
   }
5730

5731
   op_t *op = vcode_add_op(VCODE_OP_CANON_VALUE);
283✔
5732
   vcode_add_arg(op, ptr);
283✔
5733
   vcode_add_arg(op, len);
283✔
5734

5735
   VCODE_ASSERT(vcode_reg_kind(ptr) == VCODE_TYPE_POINTER,
283✔
5736
                "canon value ptr argument must be pointer");
5737
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
283✔
5738
                "canon value len argument must be offset");
5739

5740
   vcode_type_t vchar = vtype_char();
283✔
5741
   return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar)));
283✔
5742
}
5743

5744
void emit_debug_info(const loc_t *loc)
1,804,460✔
5745
{
5746
   if (!loc_invalid_p(loc))
1,804,460✔
5747
      vcode_block_data()->last_loc = *loc;
1,709,610✔
5748
}
1,804,460✔
5749

5750
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
3,729✔
5751
{
5752
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
181,905✔
5753
      if (other->args.items[0] == context && other->ident == name)
7,866✔
5754
         return other->result;
1,285✔
5755
   }
5756

5757
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
2,444✔
5758
   vcode_add_arg(op, context);
2,444✔
5759
   op->ident = name;
2,444✔
5760

5761
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
2,444✔
5762
                "first argument to link var must be context");
5763

5764
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
2,444✔
5765
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
75✔
5766
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
75✔
5767
   }
5768
   else {
5769
      op->result = vcode_add_reg(vtype_pointer(type));
2,369✔
5770
      vcode_reg_data(op->result)->bounds = type;
2,369✔
5771
   }
5772

5773
   return op->result;
2,444✔
5774
}
5775

5776
vcode_reg_t emit_link_package(ident_t name)
16,853✔
5777
{
5778
   VCODE_FOR_EACH_OP(other) {
688,291✔
5779
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
679,107✔
5780
         return other->result;
4,612✔
5781
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
674,495✔
5782
         return other->result;
3,057✔
5783
   }
5784

5785
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
9,184✔
5786
   op->ident = name;
9,184✔
5787

5788
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
9,184✔
5789

5790
   return (op->result = vcode_add_reg(vtype_context(name)));
9,184✔
5791
}
5792

5793
vcode_reg_t emit_link_instance(ident_t name, vcode_reg_t locus)
99✔
5794
{
5795
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_INSTANCE) {
519✔
5796
      if (other->ident == name)
39✔
5797
         return other->result;
24✔
5798
   }
5799

5800
   op_t *op = vcode_add_op(VCODE_OP_LINK_INSTANCE);
75✔
5801
   vcode_add_arg(op, locus);
75✔
5802
   op->ident = name;
75✔
5803

5804
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
75✔
5805
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
75✔
5806
                "locus argument to link instnance must be a debug locus");
5807

5808
   return (op->result = vcode_add_reg(vtype_context(name)));
75✔
5809
}
5810

5811
static void vcode_write_unit(vcode_unit_t unit, fbuf_t *f,
16,414✔
5812
                             ident_wr_ctx_t ident_wr_ctx,
5813
                             loc_wr_ctx_t *loc_wr_ctx)
5814
{
5815
   write_u8(unit->kind, f);
17,008✔
5816
   ident_write(unit->name, ident_wr_ctx);
17,008✔
5817
   fbuf_put_int(f, unit->result);
17,008✔
5818
   fbuf_put_int(f, unit->flags);
17,008✔
5819
   fbuf_put_int(f, unit->depth);
17,008✔
5820

5821
   if (unit->offset < 0) {
17,008✔
5822
      object_t *obj = object_from_locus(unit->module, unit->offset, NULL);
×
5823
      object_locus(obj, &unit->module, &unit->offset);
×
5824
   }
5825

5826
   ident_write(unit->module, ident_wr_ctx);
17,008✔
5827
   fbuf_put_uint(f, unit->offset);
17,008✔
5828

5829
   if (unit->context != NULL) {
17,008✔
5830
      vcode_select_unit(unit);
16,420✔
5831
      vcode_select_unit(vcode_unit_context());
16,420✔
5832
      ident_write(vcode_unit_name(), ident_wr_ctx);
16,420✔
5833
      vcode_close();
16,420✔
5834
   }
5835
   else
5836
      ident_write(NULL, ident_wr_ctx);
588✔
5837

5838
   fbuf_put_uint(f, unit->blocks.count);
17,008✔
5839
   for (unsigned i = 0; i < unit->blocks.count; i++) {
120,544✔
5840
      const block_t *b = &(unit->blocks.items[i]);
103,536✔
5841
      fbuf_put_uint(f, b->ops.count);
103,536✔
5842

5843
      for (unsigned j = 0; j < b->ops.count; j++) {
1,165,840✔
5844
         op_t *op = &(b->ops.items[j]);
1,062,300✔
5845

5846
         if (op->kind == VCODE_OP_DEBUG_LOCUS && op->value < 0) {
1,062,300✔
5847
            object_t *obj = object_from_locus(op->ident, op->value, NULL);
×
5848
            object_locus(obj, &op->ident, (ptrdiff_t *)&op->value);
×
5849
         }
5850

5851
         fbuf_put_uint(f, op->kind);
1,062,300✔
5852
         fbuf_put_uint(f, op->result);
1,062,300✔
5853
         loc_write(&(op->loc), loc_wr_ctx);
1,062,300✔
5854

5855
         fbuf_put_uint(f, op->args.count);
1,062,300✔
5856
         for (unsigned k = 0; k < op->args.count; k++)
2,985,650✔
5857
            fbuf_put_uint(f, op->args.items[k]);
1,923,350✔
5858

5859
         if (OP_HAS_TARGET(op->kind)) {
1,062,300✔
5860
            fbuf_put_uint(f, op->targets.count);
74,977✔
5861
            for (unsigned k = 0; k < op->targets.count; k++)
198,168✔
5862
               fbuf_put_uint(f, op->targets.items[k]);
123,191✔
5863
         }
5864

5865
         if (OP_HAS_TYPE(op->kind))
1,062,300✔
5866
            fbuf_put_uint(f, op->type);
247,902✔
5867
         if (OP_HAS_ADDRESS(op->kind))
1,062,300✔
5868
            fbuf_put_uint(f, op->address);
95,965✔
5869
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
1,062,300✔
5870
            ident_write(op->func, ident_wr_ctx);
57,506✔
5871
         if (OP_HAS_SUBKIND(op->kind))
1,062,300✔
5872
            fbuf_put_uint(f, op->subkind);
24,399✔
5873
         if (OP_HAS_CMP(op->kind))
1,062,300✔
5874
            fbuf_put_uint(f, op->cmp);
41,259✔
5875
         if (OP_HAS_VALUE(op->kind))
1,062,300✔
5876
            fbuf_put_int(f, op->value);
211,656✔
5877
         if (OP_HAS_REAL(op->kind))
1,062,300✔
5878
            write_double(op->real, f);
3,869✔
5879
         if (OP_HAS_COMMENT(op->kind))
1,062,300✔
5880
            ;   // Do not save comments
5881
         if (OP_HAS_DIM(op->kind))
1,062,300✔
5882
            fbuf_put_uint(f, op->dim);
73,505✔
5883
         if (OP_HAS_HOPS(op->kind))
1,062,300✔
5884
            fbuf_put_uint(f, op->hops);
14,599✔
5885
         if (OP_HAS_FIELD(op->kind))
1,062,300✔
5886
            fbuf_put_uint(f, op->field);
23,226✔
5887
         if (OP_HAS_TAG(op->kind))
1,062,300✔
5888
            fbuf_put_uint(f, op->tag);
×
5889
      }
5890
   }
5891

5892
   fbuf_put_uint(f, unit->regs.count);
17,008✔
5893
   for (unsigned i = 0; i < unit->regs.count; i++) {
958,597✔
5894
      const reg_t *r = &(unit->regs.items[i]);
941,589✔
5895
      fbuf_put_uint(f, r->type);
941,589✔
5896
      fbuf_put_uint(f, r->bounds);
941,589✔
5897
   }
5898

5899
   fbuf_put_uint(f, unit->types.count);
17,008✔
5900
   for (unsigned i = 0; i < unit->types.count; i++) {
294,342✔
5901
      const vtype_t *t = &(unit->types.items[i]);
277,334✔
5902
      fbuf_put_uint(f, t->kind);
277,334✔
5903
      switch (t->kind) {
277,334✔
5904
      case VCODE_TYPE_INT:
187,885✔
5905
      case VCODE_TYPE_OFFSET:
5906
         fbuf_put_int(f, t->repr);
187,885✔
5907
         fbuf_put_int(f, t->low);
187,885✔
5908
         fbuf_put_int(f, t->high);
187,885✔
5909
         break;
187,885✔
5910

5911
      case VCODE_TYPE_REAL:
6,302✔
5912
         write_double(t->rlow, f);
6,302✔
5913
         write_double(t->rhigh, f);
6,302✔
5914
         break;
6,302✔
5915

5916
      case VCODE_TYPE_CARRAY:
24,881✔
5917
      case VCODE_TYPE_UARRAY:
5918
         fbuf_put_uint(f, t->dims);
24,881✔
5919
         fbuf_put_uint(f, t->size);
24,881✔
5920
         fbuf_put_uint(f, t->elem);
24,881✔
5921
         fbuf_put_uint(f, t->bounds);
24,881✔
5922
         break;
24,881✔
5923

5924
      case VCODE_TYPE_ACCESS:
24,047✔
5925
      case VCODE_TYPE_POINTER:
5926
         fbuf_put_uint(f, t->pointed);
24,047✔
5927
         break;
24,047✔
5928

5929
      case VCODE_TYPE_FILE:
1,437✔
5930
      case VCODE_TYPE_SIGNAL:
5931
      case VCODE_TYPE_RESOLUTION:
5932
      case VCODE_TYPE_CLOSURE:
5933
         fbuf_put_uint(f, t->base);
1,437✔
5934
         break;
1,437✔
5935

5936
      case VCODE_TYPE_OPAQUE:
5937
      case VCODE_TYPE_DEBUG_LOCUS:
5938
         break;
5939

5940
      case VCODE_TYPE_CONTEXT:
20,415✔
5941
         ident_write(t->name, ident_wr_ctx);
20,415✔
5942
         break;
20,415✔
5943

5944
      case VCODE_TYPE_RECORD:
4,571✔
5945
         ident_write(t->name, ident_wr_ctx);
4,571✔
5946
         fbuf_put_uint(f, t->fields.count);
4,571✔
5947
         for (unsigned j = 0; j < t->fields.count; j++)
25,837✔
5948
            fbuf_put_uint(f, t->fields.items[j]);
21,266✔
5949
         break;
5950
      }
5951
   }
277,334✔
5952

5953
   fbuf_put_uint(f, unit->vars.count);
17,008✔
5954
   for (unsigned i = 0; i < unit->vars.count; i++) {
43,708✔
5955
      const var_t *v = &(unit->vars.items[i]);
26,700✔
5956
      fbuf_put_uint(f, v->type);
26,700✔
5957
      fbuf_put_uint(f, v->bounds);
26,700✔
5958
      ident_write(v->name, ident_wr_ctx);
26,700✔
5959
      fbuf_put_uint(f, v->flags);
26,700✔
5960
   }
5961

5962
   fbuf_put_uint(f, unit->params.count);
17,008✔
5963
   for (unsigned i = 0; i < unit->params.count; i++) {
66,126✔
5964
      const param_t *p = &(unit->params.items[i]);
49,118✔
5965
      fbuf_put_uint(f, p->type);
49,118✔
5966
      fbuf_put_uint(f, p->bounds);
49,118✔
5967
      ident_write(p->name, ident_wr_ctx);
49,118✔
5968
      fbuf_put_uint(f, p->reg);
49,118✔
5969
   }
5970

5971
   if (unit->next != NULL)
17,008✔
5972
      vcode_write_unit(unit->next, f, ident_wr_ctx, loc_wr_ctx);
15,826✔
5973

5974
   if (unit->children != NULL)
17,008✔
5975
      vcode_write_unit(unit->children, f, ident_wr_ctx, loc_wr_ctx);
5976
}
16,414✔
5977

5978
void vcode_write(vcode_unit_t unit, fbuf_t *f, ident_wr_ctx_t ident_ctx,
588✔
5979
                 loc_wr_ctx_t *loc_ctx)
5980
{
5981
   assert(unit->context == NULL);
588✔
5982

5983
   write_u8(VCODE_VERSION, f);
588✔
5984

5985
   vcode_write_unit(unit, f, ident_ctx, loc_ctx);
588✔
5986
   write_u8(0xff, f);  // End marker
588✔
5987
}
588✔
5988

5989
static vcode_unit_t vcode_read_unit(fbuf_t *f, ident_rd_ctx_t ident_rd_ctx,
325,951✔
5990
                                    loc_rd_ctx_t *loc_rd_ctx)
5991
{
5992
   const uint8_t marker = read_u8(f);
325,951✔
5993
   if (marker == 0xff)
325,951✔
5994
      return false;
5995

5996
   vcode_unit_t unit = xcalloc(sizeof(struct _vcode_unit));
321,803✔
5997
   unit->kind   = marker;
321,803✔
5998
   unit->name   = ident_read(ident_rd_ctx);
321,803✔
5999
   unit->result = fbuf_get_int(f);
321,803✔
6000
   unit->flags  = fbuf_get_int(f);
321,803✔
6001
   unit->depth  = fbuf_get_int(f);
321,803✔
6002
   unit->module = ident_read(ident_rd_ctx);
321,803✔
6003
   unit->offset = fbuf_get_uint(f);
321,803✔
6004

6005
   ident_t context_name = ident_read(ident_rd_ctx);
321,803✔
6006
   if (context_name != NULL) {
321,803✔
6007
      unit->context = vcode_find_unit(context_name);
317,655✔
6008
      if (unit->context == NULL)
317,655✔
6009
         fatal("%s references nonexistent context %s", fbuf_file_name(f),
×
6010
               istr(context_name));
6011

6012
      vcode_add_child(unit->context, unit);
317,655✔
6013
   }
6014
   else
6015
      unit->context = NULL;
4,148✔
6016

6017
   block_array_resize(&(unit->blocks), fbuf_get_uint(f), 0);
321,803✔
6018
   for (unsigned i = 0; i < unit->blocks.count; i++) {
2,559,680✔
6019
      block_t *b = &(unit->blocks.items[i]);
2,237,880✔
6020
      op_array_resize(&(b->ops), fbuf_get_uint(f), 0);
2,237,880✔
6021

6022
      for (unsigned j = 0; j < b->ops.count; j++) {
24,267,100✔
6023
         op_t *op = &(b->ops.items[j]);
22,029,300✔
6024

6025
         op->kind = fbuf_get_uint(f);
22,029,300✔
6026
         op->result = fbuf_get_uint(f);
22,029,300✔
6027
         loc_read(&(op->loc), loc_rd_ctx);
22,029,300✔
6028

6029
         vcode_reg_array_resize(&(op->args), fbuf_get_uint(f), 0);
22,029,300✔
6030
         for (unsigned k = 0; k < op->args.count; k++)
50,073,000✔
6031
            op->args.items[k] = fbuf_get_uint(f);
28,043,800✔
6032

6033
         if (OP_HAS_TARGET(op->kind)) {
22,029,300✔
6034
            vcode_block_array_resize(&(op->targets), fbuf_get_uint(f), 0);
918,916✔
6035
            for (unsigned k = 0; k < op->targets.count; k++)
3,292,460✔
6036
               op->targets.items[k] = fbuf_get_uint(f);
2,373,540✔
6037
         }
6038

6039
         if (OP_HAS_TYPE(op->kind))
22,029,300✔
6040
            op->type = fbuf_get_uint(f);
9,940,040✔
6041
         if (OP_HAS_ADDRESS(op->kind))
22,029,300✔
6042
            op->address = fbuf_get_uint(f);
988,983✔
6043
         if (OP_HAS_FUNC(op->kind) || OP_HAS_IDENT(op->kind))
22,029,300✔
6044
            op->func = ident_read(ident_rd_ctx);
524,757✔
6045
         if (OP_HAS_SUBKIND(op->kind))
22,029,300✔
6046
            op->subkind = fbuf_get_uint(f);
177,660✔
6047
         if (OP_HAS_CMP(op->kind))
22,029,300✔
6048
            op->cmp = fbuf_get_uint(f);
577,081✔
6049
         if (OP_HAS_VALUE(op->kind))
22,029,300✔
6050
            op->value = fbuf_get_int(f);
9,521,420✔
6051
         if (OP_HAS_REAL(op->kind))
22,029,300✔
6052
            op->real = read_double(f);
26,847✔
6053
         if (OP_HAS_COMMENT(op->kind))
22,029,300✔
6054
            op->comment = NULL;
1,013,260✔
6055
         if (OP_HAS_DIM(op->kind))
22,029,300✔
6056
            op->dim = fbuf_get_uint(f);
938,188✔
6057
         if (OP_HAS_HOPS(op->kind))
22,029,300✔
6058
            op->hops = fbuf_get_uint(f);
101,260✔
6059
         if (OP_HAS_FIELD(op->kind))
22,029,300✔
6060
            op->field = fbuf_get_uint(f);
13,419✔
6061
         if (OP_HAS_TAG(op->kind))
22,029,300✔
6062
            op->tag = fbuf_get_uint(f);
×
6063
      }
6064
   }
6065

6066
   reg_array_resize(&(unit->regs), fbuf_get_uint(f), 0);
321,803✔
6067
   for (unsigned i = 0; i < unit->regs.count; i++) {
20,148,700✔
6068
      reg_t *r = &(unit->regs.items[i]);
19,826,900✔
6069
      r->type = fbuf_get_uint(f);
19,826,900✔
6070
      r->bounds = fbuf_get_uint(f);
19,826,900✔
6071
   }
6072

6073
   vtype_array_resize(&(unit->types), fbuf_get_uint(f), 0);
321,803✔
6074
   for (unsigned i = 0; i < unit->types.count; i++) {
7,224,690✔
6075
      vtype_t *t = &(unit->types.items[i]);
6,902,890✔
6076
      switch ((t->kind = fbuf_get_uint(f))) {
6,902,890✔
6077
      case VCODE_TYPE_INT:
5,530,990✔
6078
      case VCODE_TYPE_OFFSET:
6079
         t->repr = fbuf_get_int(f);
5,530,990✔
6080
         t->low = fbuf_get_int(f);
5,530,990✔
6081
         t->high = fbuf_get_int(f);
5,530,990✔
6082
         break;
5,530,990✔
6083

6084
      case VCODE_TYPE_REAL:
70,887✔
6085
         t->rlow = read_double(f);
70,887✔
6086
         t->rhigh = read_double(f);
70,887✔
6087
         break;
70,887✔
6088

6089
      case VCODE_TYPE_CARRAY:
506,117✔
6090
      case VCODE_TYPE_UARRAY:
6091
         t->dims = fbuf_get_uint(f);
506,117✔
6092
         t->size = fbuf_get_uint(f);
506,117✔
6093
         t->elem = fbuf_get_uint(f);
506,117✔
6094
         t->bounds = fbuf_get_uint(f);
506,117✔
6095
         break;
506,117✔
6096

6097
      case VCODE_TYPE_POINTER:
340,061✔
6098
      case VCODE_TYPE_ACCESS:
6099
         t->base = fbuf_get_uint(f);
340,061✔
6100
         break;
340,061✔
6101

6102
      case VCODE_TYPE_FILE:
2,748✔
6103
      case VCODE_TYPE_SIGNAL:
6104
      case VCODE_TYPE_RESOLUTION:
6105
      case VCODE_TYPE_CLOSURE:
6106
         t->base = fbuf_get_uint(f);
2,748✔
6107
         break;
2,748✔
6108

6109
      case VCODE_TYPE_OPAQUE:
6110
      case VCODE_TYPE_DEBUG_LOCUS:
6111
         break;
6112

6113
      case VCODE_TYPE_CONTEXT:
332,426✔
6114
         t->name = ident_read(ident_rd_ctx);
332,426✔
6115
         break;
332,426✔
6116

6117
      case VCODE_TYPE_RECORD:
4,140✔
6118
         {
6119
            t->name = ident_read(ident_rd_ctx);
4,140✔
6120
            vcode_type_array_resize(&(t->fields), fbuf_get_uint(f), 0);
4,140✔
6121
            for (unsigned j = 0; j < t->fields.count; j++)
19,448✔
6122
               t->fields.items[j] = fbuf_get_uint(f);
15,308✔
6123
            break;
6124
         }
6125
      }
6126
   }
6,902,890✔
6127

6128
   var_array_resize(&(unit->vars), fbuf_get_uint(f), 0);
321,803✔
6129
   for (unsigned i = 0; i < unit->vars.count; i++) {
616,819✔
6130
      var_t *v = &(unit->vars.items[i]);
295,016✔
6131
      v->type = fbuf_get_uint(f);
295,016✔
6132
      v->bounds = fbuf_get_uint(f);
295,016✔
6133
      v->name = ident_read(ident_rd_ctx);
295,016✔
6134
      v->flags = fbuf_get_uint(f);
295,016✔
6135
   }
6136

6137
   param_array_resize(&(unit->params), fbuf_get_uint(f), 0);
321,803✔
6138
   for (unsigned i = 0; i < unit->params.count; i++) {
1,171,240✔
6139
      param_t *p = &(unit->params.items[i]);
849,440✔
6140
      p->type = fbuf_get_uint(f);
849,440✔
6141
      p->bounds = fbuf_get_uint(f);
849,440✔
6142
      p->name = ident_read(ident_rd_ctx);
849,440✔
6143
      p->reg = fbuf_get_uint(f);
849,440✔
6144
   }
6145

6146
   vcode_registry_add(unit);
321,803✔
6147

6148
   return unit;
321,803✔
6149
}
6150

6151
vcode_unit_t vcode_read(fbuf_t *f, ident_rd_ctx_t ident_ctx,
4,148✔
6152
                        loc_rd_ctx_t *loc_ctx)
6153
{
6154
   const uint8_t version = read_u8(f);
4,148✔
6155
   if (version != VCODE_VERSION) {
4,148✔
6156
      diag_t *d = diag_new(DIAG_FATAL, NULL);
×
6157
      diag_printf(d, "%s was created with vcode format version %d "
×
6158
                  "(expected %d)", fbuf_file_name(f), version, VCODE_VERSION);
6159
      diag_hint(d, NULL, "this file was most likely created with an earlier "
×
6160
                "version of " PACKAGE_NAME " and should be reanalysed");
6161
      diag_emit(d);
×
6162
      fatal_exit(EXIT_FAILURE);
×
6163
   }
6164

6165
   vcode_unit_t vu, root = NULL;
6166
   while ((vu = vcode_read_unit(f, ident_ctx, loc_ctx))) {
325,951✔
6167
      if (root == NULL)
321,803✔
6168
         root = vu;
4,148✔
6169
   }
6170

6171
   return root;
4,148✔
6172
}
6173

6174
#if VCODE_CHECK_UNIONS
6175
#define OP_USE_COUNT_U0(x)                                              \
6176
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6177
#define OP_USE_COUNT_U1(x)                                              \
6178
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6179
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6180
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6181

6182
__attribute__((constructor))
6183
static void vcode_check_unions(void)
6184
{
6185
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6186
   for (int i = 0; i < 256; i++) {
6187
      assert(OP_USE_COUNT_U0(i) <= 1);
6188
      assert(OP_USE_COUNT_U1(i) <= 1);
6189
   }
6190
}
6191
#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