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

nickg / nvc / 16099227452

06 Jul 2025 12:45PM UTC coverage: 92.335% (+0.05%) from 92.284%
16099227452

push

github

nickg
Handle underscores in Verilog decimal literals

Fixes #1230

18 of 20 new or added lines in 1 file covered. (90.0%)

598 existing lines in 16 files now uncovered.

71069 of 76969 relevant lines covered (92.33%)

564781.41 hits per line

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

96.19
/src/vlog/vlog-lower.c
1
//
2
//  Copyright (C) 2023-2025  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 "common.h"
20
#include "diag.h"
21
#include "hash.h"
22
#include "ident.h"
23
#include "mir/mir-node.h"
24
#include "mir/mir-unit.h"
25
#include "type.h"
26
#include "vlog/vlog-defs.h"
27
#include "vlog/vlog-node.h"
28
#include "vlog/vlog-number.h"
29
#include "vlog/vlog-phase.h"
30
#include "vlog/vlog-util.h"
31

32
#include <assert.h>
33
#include <inttypes.h>
34
#include <string.h>
35
#include <stdlib.h>
36

37
typedef struct {
38
   mir_type_t  type;
39
   unsigned    size;
40
   mir_value_t temp;
41
} type_info_t;
42

43
typedef struct {
44
   mir_value_t  nets;
45
   unsigned     size;
46
   type_info_t *base;
47
} vlog_lvalue_t;
48

49
STATIC_ASSERT(sizeof(vlog_lvalue_t) <= 16);
50

51
#define CANNOT_HANDLE(v) do {                                           \
52
      fatal_at(vlog_loc(v), "cannot handle %s in %s" ,                  \
53
               vlog_kind_str(vlog_kind(v)), __FUNCTION__);              \
54
   } while (0)
55

56
#define PUSH_DEBUG_INFO(mu, v)                                          \
57
   __attribute__((cleanup(_mir_pop_debug_info), unused))                \
58
   const mir_saved_loc_t _old_loc =                                     \
59
      _mir_push_debug_info((mu), vlog_loc((v)));
60

61
static void vlog_lower_stmts(mir_unit_t *mu, vlog_node_t v);
62
static mir_value_t vlog_lower_rvalue(mir_unit_t *mu, vlog_node_t v);
63

64
static type_info_t *vlog_type_info(mir_unit_t *mu, vlog_node_t v)
1,956✔
65
{
66
   assert(vlog_kind(v) == V_DATA_TYPE);
1,956✔
67

68
   type_info_t *ti = mir_get_priv(mu, v);
1,956✔
69
   if (ti == NULL) {
1,956✔
70
      ti = mir_malloc(mu, sizeof(type_info_t));
1,956✔
71
      ti->size = vlog_size(v);
1,956✔
72
      ti->type = mir_vec4_type(mu, ti->size, false);
1,956✔
73
      ti->temp = MIR_NULL_VALUE;
1,956✔
74
   }
75

76
   return ti;
1,956✔
77
}
78

79
static mir_value_t vlog_get_temp(mir_unit_t *mu, type_info_t *ti)
224✔
80
{
81
   if (mir_is_null(ti->temp)) {
224✔
82
      mir_type_t t_array = mir_carray_type(mu, ti->size, mir_logic_type(mu));
224✔
83
      ti->temp = mir_add_var(mu, t_array, MIR_NULL_STAMP, ident_uniq("tmp"),
224✔
84
                             MIR_VAR_TEMP);
85
   }
86

87
   return ti->temp;
224✔
88
}
89

90
static vlog_lvalue_t vlog_lower_lvalue_ref(mir_unit_t *mu, vlog_node_t v)
1,168✔
91
{
92
   vlog_node_t decl = vlog_ref(v);
1,168✔
93
   if (vlog_kind(decl) == V_PORT_DECL)
1,168✔
94
      decl = vlog_ref(decl);
184✔
95

96
   int hops;
1,168✔
97
   mir_value_t var = mir_search_object(mu, decl, &hops);
1,168✔
98
   assert(!mir_is_null(var));
1,168✔
99

100
   assert(hops > 0);
1,168✔
101
   mir_value_t upref = mir_build_var_upref(mu, hops, var.id);
1,168✔
102

103
   type_info_t *ti = vlog_type_info(mu, vlog_type(decl));
1,168✔
104

105
   vlog_lvalue_t result = {
2,336✔
106
      .nets = mir_build_load(mu, upref),
1,168✔
107
      .size = ti->size,
1,168✔
108
      .base = ti,
109
   };
110
   return result;
1,168✔
111
}
112

113
static vlog_lvalue_t vlog_lower_lvalue(mir_unit_t *mu, vlog_node_t v)
1,168✔
114
{
115
   PUSH_DEBUG_INFO(mu, v);
2,336✔
116

117
   switch (vlog_kind(v)) {
1,168✔
118
   case V_REF:
1,140✔
119
      return vlog_lower_lvalue_ref(mu, v);
1,140✔
120
   case V_BIT_SELECT:
28✔
121
      {
122
         vlog_lvalue_t ref = vlog_lower_lvalue_ref(mu, vlog_value(v));
28✔
123

124
         assert(vlog_params(v) == 1);
28✔
125
         mir_value_t p0 = vlog_lower_rvalue(mu, vlog_param(v, 0));
28✔
126

127
         mir_type_t p0_type = mir_get_type(mu, p0);
28✔
128
         if (mir_get_class(mu, p0_type) == MIR_TYPE_VEC4) {
28✔
129
            // TODO: check X/Z handling
UNCOV
130
            mir_type_t t_vec2 =
×
UNCOV
131
               mir_vec2_type(mu, mir_get_size(mu, p0_type), false);
×
UNCOV
132
            p0 = mir_build_cast(mu, t_vec2, p0);
×
133
         }
134

135
         mir_type_t t_offset = mir_offset_type(mu);
28✔
136
         mir_value_t off = mir_build_cast(mu, t_offset, p0);
28✔
137

138
         vlog_lvalue_t lvalue = {
56✔
139
            .nets = mir_build_array_ref(mu, ref.nets, off),
28✔
140
            .size = 1,
141
            .base = ref.base,
28✔
142
         };
143
         return lvalue;
28✔
144
      }
UNCOV
145
   default:
×
146
      CANNOT_HANDLE(v);
1,168✔
147
   }
148
}
149

150
static void vlog_assign_variable(mir_unit_t *mu, vlog_node_t target,
368✔
151
                                 mir_value_t value)
152
{
153
   assert(mir_is_vector(mu, value));
368✔
154

155
   vlog_lvalue_t lvalue = vlog_lower_lvalue(mu, target);
368✔
156

157
   mir_type_t t_offset = mir_offset_type(mu);
368✔
158
   mir_type_t t_vec = mir_vec4_type(mu, lvalue.size, false);
368✔
159

160
   mir_value_t resize = mir_build_cast(mu, t_vec, value);
368✔
161
   mir_value_t count = mir_const(mu, t_offset, lvalue.size);
368✔
162

163
   mir_value_t tmp = MIR_NULL_VALUE;
368✔
164
   if (lvalue.size > 1)
368✔
165
      tmp = vlog_get_temp(mu, lvalue.base);
164✔
166

167
   mir_value_t unpacked = mir_build_unpack(mu, resize, 0, tmp);
368✔
168

169
   mir_build_deposit_signal(mu, lvalue.nets, count, unpacked);
368✔
170

171
   // Delay one delta cycle to see the update
172

173
   mir_value_t zero_time = mir_const(mu, mir_time_type(mu), 0);
368✔
174

175
   mir_block_t resume_bb = mir_add_block(mu);
368✔
176
   mir_build_wait(mu, resume_bb, zero_time);
368✔
177

178
   mir_set_cursor(mu, resume_bb, MIR_APPEND);
368✔
179
}
368✔
180

181
static mir_value_t vlog_lower_unary(mir_unit_t *mu, vlog_node_t v)
48✔
182
{
183
   mir_value_t input = vlog_lower_rvalue(mu, vlog_value(v));
48✔
184
   mir_type_t type = mir_get_type(mu, input);
48✔
185

186
   mir_vec_op_t mop;
48✔
187
   switch (vlog_subkind(v)) {
48✔
188
   case V_UNARY_BITNEG: mop = MIR_VEC_BIT_NOT; break;
189
   case V_UNARY_NOT:    mop = MIR_VEC_LOG_NOT; break;
190
   case V_UNARY_NEG:    mop = MIR_VEC_SUB; break;
UNCOV
191
   default:
×
UNCOV
192
      CANNOT_HANDLE(v);
×
193
   }
194

195
   return mir_build_unary(mu, mop, type, input);
48✔
196
}
197

198
static mir_value_t vlog_lower_binary(mir_unit_t *mu, vlog_node_t v)
380✔
199
{
200
   mir_value_t left = vlog_lower_rvalue(mu, vlog_left(v));
380✔
201
   mir_value_t right = vlog_lower_rvalue(mu, vlog_right(v));
380✔
202

203
   assert(mir_is_vector(mu, left));
380✔
204
   assert(mir_is_vector(mu, right));
380✔
205

206
   mir_type_t ltype = mir_get_type(mu, left);
380✔
207
   mir_type_t rtype = mir_get_type(mu, right);
380✔
208

209
   const mir_class_t lclass = mir_get_class(mu, ltype);
380✔
210
   const mir_class_t rclass = mir_get_class(mu, rtype);
380✔
211

212
   const int lsize = mir_get_size(mu, ltype);
380✔
213
   const int rsize = mir_get_size(mu, rtype);
380✔
214

215
   mir_type_t type;
380✔
216
   if (lclass == MIR_TYPE_VEC4 || rclass == MIR_TYPE_VEC4)
380✔
217
      type = mir_vec4_type(mu, MAX(lsize, rsize), false);
380✔
218
   else
UNCOV
219
      type = mir_vec2_type(mu, MAX(lsize, rsize), false);
×
220

221
   mir_value_t lcast = mir_build_cast(mu, type, left);
380✔
222
   mir_value_t rcast = mir_build_cast(mu, type, right);
380✔
223

224
   mir_vec_op_t mop;
380✔
225
   switch (vlog_subkind(v)) {
380✔
226
   case V_BINARY_AND:      mop = MIR_VEC_BIT_AND; break;
227
   case V_BINARY_OR:       mop = MIR_VEC_BIT_OR; break;
12✔
228
   case V_BINARY_LOG_AND:  mop = MIR_VEC_LOG_AND; break;
16✔
229
   case V_BINARY_LOG_OR:   mop = MIR_VEC_LOG_OR; break;
28✔
230
   case V_BINARY_LT:       mop = MIR_VEC_LT; break;
12✔
231
   case V_BINARY_LEQ:      mop = MIR_VEC_LEQ; break;
8✔
232
   case V_BINARY_GT:       mop = MIR_VEC_GT; break;
8✔
233
   case V_BINARY_GEQ:      mop = MIR_VEC_GEQ; break;
8✔
234
   case V_BINARY_LOG_EQ:   mop = MIR_VEC_LOG_EQ; break;
16✔
UNCOV
235
   case V_BINARY_LOG_NEQ:  mop = MIR_VEC_LOG_NEQ; break;
×
236
   case V_BINARY_CASE_EQ:  mop = MIR_VEC_CASE_EQ; break;
36✔
237
   case V_BINARY_CASE_NEQ: mop = MIR_VEC_CASE_NEQ; break;
180✔
238
   case V_BINARY_PLUS:     mop = MIR_VEC_ADD; break;
24✔
239
   case V_BINARY_MINUS:    mop = MIR_VEC_SUB; break;
4✔
240
   case V_BINARY_SHIFT_LL: mop = MIR_VEC_SLL; break;
4✔
UNCOV
241
   case V_BINARY_SHIFT_RL: mop = MIR_VEC_SRL; break;
×
UNCOV
242
   default:
×
UNCOV
243
      CANNOT_HANDLE(v);
×
244
   }
245

246
   return mir_build_binary(mu, mop, type, lcast, rcast);
380✔
247
}
248

249
static mir_value_t vlog_lower_systf_param(mir_unit_t *mu, vlog_node_t v)
992✔
250
{
251
   switch (vlog_kind(v)) {
992✔
252
   case V_REF:
888✔
253
   case V_STRING:
254
   case V_NUMBER:
255
   case V_EMPTY:
256
      return MIR_NULL_VALUE;
888✔
257
   case V_UNARY:
104✔
258
   case V_BINARY:
259
   case V_SYS_FCALL:
260
   case V_PREFIX:
261
   case V_POSTFIX:
262
      // TODO: these should not be evaluated until vpi_get_value is called
263
      return vlog_lower_rvalue(mu, v);
104✔
UNCOV
264
   default:
×
UNCOV
265
      CANNOT_HANDLE(v);
×
266
   }
267
}
268

269
static mir_value_t vlog_lower_sys_tfcall(mir_unit_t *mu, vlog_node_t v)
756✔
270
{
271
   const int nparams = vlog_params(v);
756✔
272
   mir_value_t *args LOCAL =
1,512✔
273
      xmalloc_array((nparams * 2) + 1, sizeof(mir_value_t));
756✔
274
   int actual = 0;
756✔
275
   mir_type_t t_offset = mir_offset_type(mu);
756✔
276
   for (int i = 0; i < nparams; i++) {
1,748✔
277
      mir_value_t arg = vlog_lower_systf_param(mu, vlog_param(v, i));
992✔
278
      if (mir_is_null(arg))
992✔
279
         continue;
888✔
280

281
      mir_type_t type = mir_get_type(mu, arg);
104✔
282
      switch (mir_get_class(mu, type)) {
104✔
283
      case MIR_TYPE_VEC4:
36✔
284
         args[actual++] = mir_const(mu, t_offset, mir_get_size(mu, type));
36✔
285
         args[actual++] = arg;
36✔
286
         break;
36✔
287
      case MIR_TYPE_VEC2:
68✔
288
         {
289
            // TODO: remove the cast
290
            const int size = mir_get_size(mu, type);
68✔
291
            mir_type_t t_vec4 = mir_vec4_type(mu, size, false);
68✔
292
            args[actual++] = mir_const(mu, t_offset, size);
68✔
293
            args[actual++] = mir_build_cast(mu, t_vec4, arg);
68✔
294
         }
295
         break;
68✔
UNCOV
296
      default:
×
297
         should_not_reach_here();
298
      }
299
   }
300

301
   mir_value_t locus = mir_build_locus(mu, vlog_to_object(v));
756✔
302

303
   mir_type_t type = MIR_NULL_TYPE;
756✔
304
   if (vlog_kind(v) == V_SYS_FCALL)
756✔
305
      type = mir_vec2_type(mu, 64, false);  // XXX: hack for $time
52✔
306

307
   return mir_build_syscall(mu, vlog_ident(v), type, MIR_NULL_STAMP,
756✔
308
                            locus, args, actual);
309
}
310

311
static mir_value_t vlog_lower_resolved(mir_unit_t *mu, vlog_node_t v)
564✔
312
{
313
   switch (vlog_kind(v)) {
656✔
314
   case V_PORT_DECL:
92✔
315
   case V_REF:
316
      return vlog_lower_resolved(mu, vlog_ref(v));
92✔
317
   case V_VAR_DECL:
564✔
318
   case V_NET_DECL:
319
      {
320
         int hops;
564✔
321
         mir_value_t var = mir_search_object(mu, v, &hops);
564✔
322
         assert(!mir_is_null(var));
564✔
323

324
         assert(hops > 0);
564✔
325
         mir_value_t upref = mir_build_var_upref(mu, hops, var.id);
564✔
326
         mir_value_t nets = mir_build_load(mu, upref);
564✔
327
         return mir_build_resolved(mu, nets);
564✔
328
      }
UNCOV
329
   default:
×
330
      CANNOT_HANDLE(v);
564✔
331
   }
332
}
333

334
static mir_value_t vlog_lower_array_off(mir_unit_t *mu, vlog_node_t dt,
28✔
335
                                        vlog_node_t v)
336
{
337
   mir_value_t index = vlog_lower_rvalue(mu, v);
28✔
338

339
   mir_type_t index_type = mir_get_type(mu, index);
28✔
340
   if (mir_get_class(mu, index_type) == MIR_TYPE_VEC4) {
28✔
341
      // TODO: check X/Z handling
342
      mir_type_t vec2 = mir_vec2_type(mu, mir_get_size(mu, index_type), false);
4✔
343
      index = mir_build_cast(mu, vec2, index);
4✔
344
   }
345

346
   mir_type_t t_offset = mir_offset_type(mu);
28✔
347
   mir_value_t cast = mir_build_cast(mu, t_offset, index);
28✔
348

349
   vlog_node_t r = vlog_range(dt, 0);
28✔
350
   assert(vlog_subkind(r) == V_DIM_PACKED);
28✔
351

352
   int64_t left, right;
28✔
353
   vlog_bounds(r, &left, &right);
28✔
354

355
   if (left < right)
28✔
UNCOV
356
      return mir_build_sub(mu, t_offset, cast, mir_const(mu, t_offset, left));
×
357
   else
358
      return mir_build_sub(mu, t_offset, mir_const(mu, t_offset, left), cast);
28✔
359
}
360

361
static mir_value_t vlog_lower_rvalue_bit_select(mir_unit_t *mu, vlog_node_t v)
16✔
362
{
363
   vlog_node_t value = vlog_value(v);
16✔
364
   assert(vlog_kind(value) == V_REF);
16✔
365

366
   mir_value_t data = vlog_lower_resolved(mu, value);
16✔
367

368
   vlog_node_t dt = vlog_type(vlog_ref(value));
16✔
369
   assert(vlog_ranges(dt) == 1);
16✔
370
   assert(vlog_params(v) == 1);
16✔
371

372
   mir_type_t t_offset = mir_offset_type(mu);
16✔
373
   mir_value_t off = vlog_lower_array_off(mu, dt, vlog_param(v, 0));
16✔
374

375
   mir_value_t cmp_low = mir_build_cmp(mu, MIR_CMP_GEQ, off,
16✔
376
                                       mir_const(mu, t_offset, 0));
377
   mir_value_t cmp_high = mir_build_cmp(mu, MIR_CMP_LT, off,
16✔
378
                                        mir_const(mu, t_offset, vlog_size(dt)));
16✔
379
   mir_value_t in_range = mir_build_and(mu, cmp_low, cmp_high);
16✔
380

381
   mir_type_t type = mir_vec4_type(mu, 1, false);
16✔
382

383
   int64_t in_range_const;
16✔
384
   if (mir_get_const(mu, in_range, &in_range_const)) {
16✔
385
      if (in_range_const) {
12✔
386
         mir_value_t ptr = mir_build_array_ref(mu, data, off);
4✔
387
         mir_value_t bit = mir_build_load(mu, ptr);
4✔
388
         return mir_build_pack(mu, type, bit);
4✔
389
      }
390
      else
391
         return mir_const_vec(mu, type, 1, 1);
8✔
392
   }
393
   else {
394
      // TODO: use a phi node here
395
      mir_value_t tmp = mir_add_var(mu, type, MIR_NULL_STAMP,
4✔
396
                                    ident_uniq("tmp"), MIR_VAR_TEMP);
397
      mir_build_store(mu, tmp, mir_const_vec(mu, type, 1, 1));
4✔
398

399
      mir_block_t guarded_bb = mir_add_block(mu);
4✔
400
      mir_block_t merge_bb = mir_add_block(mu);
4✔
401

402
      mir_build_cond(mu, in_range, guarded_bb, merge_bb);
4✔
403

404
      mir_set_cursor(mu, guarded_bb, MIR_APPEND);
4✔
405

406
      mir_value_t ptr = mir_build_array_ref(mu, data, off);
4✔
407
      mir_value_t bit = mir_build_load(mu, ptr);
4✔
408
      mir_build_store(mu, tmp, mir_build_pack(mu, type, bit));
4✔
409
      mir_build_jump(mu, merge_bb);
4✔
410

411
      mir_set_cursor(mu, merge_bb, MIR_APPEND);
4✔
412

413
      return mir_build_load(mu, tmp);
4✔
414
   }
415
}
416

417
static mir_value_t vlog_lower_rvalue(mir_unit_t *mu, vlog_node_t v)
2,272✔
418
{
419
   PUSH_DEBUG_INFO(mu, v);
4,544✔
420

421
   switch (vlog_kind(v)) {
2,272✔
422
   case V_REF:
536✔
423
      {
424
         vlog_node_t decl = vlog_ref(v);
536✔
425
         if (vlog_kind(decl) == V_LOCALPARAM)
536✔
UNCOV
426
            return vlog_lower_rvalue(mu, vlog_value(decl));
×
427

428
         mir_value_t data = vlog_lower_resolved(mu, decl);
536✔
429

430
         type_info_t *ti = vlog_type_info(mu, vlog_type(decl));
536✔
431

432
         if (ti->size == 1)
536✔
433
            data = mir_build_load(mu, data);
304✔
434

435
         return mir_build_pack(mu, ti->type, data);
536✔
436
      }
437
   case V_EVENT:
124✔
438
      {
439
         vlog_node_t value = vlog_value(v);
124✔
440

441
         mir_type_t t_offset = mir_offset_type(mu);
124✔
442

443
         vlog_lvalue_t lvalue = vlog_lower_lvalue(mu, value);
124✔
444
         mir_value_t count = mir_const(mu, t_offset, lvalue.size);
124✔
445

446
         mir_value_t event = mir_build_event_flag(mu, lvalue.nets, count);
124✔
447

448
         const v_event_kind_t ekind = vlog_subkind(v);
124✔
449
         if (ekind == V_EVENT_LEVEL)
124✔
450
            return event;
96✔
451

452
         mir_type_t t_logic = mir_vec4_type(mu, 1, false);
28✔
453

454
         mir_value_t level =
28✔
455
            mir_const_vec(mu, t_logic, ekind == V_EVENT_POSEDGE, 0);
28✔
456
         mir_value_t rvalue = vlog_lower_rvalue(mu, value);
28✔
457
         mir_value_t cmp = mir_build_cmp(mu, MIR_CMP_EQ, rvalue, level);
28✔
458

459
         return mir_build_and(mu, event, cmp);
28✔
460
      }
461
   case V_NUMBER:
1,088✔
462
      {
463

464
         number_t num = vlog_number(v);
1,088✔
465
         const int width = number_width(num);
1,088✔
466
         assert(width < 64);
1,088✔
467

468
         if (number_is_defined(num)) {
1,088✔
469
            mir_type_t t_vec2 = mir_vec2_type(mu, width, false);
1,068✔
470
            return mir_const_vec(mu, t_vec2, number_integer(num), 0);
1,068✔
471
         }
472
         else {
473
            uint64_t abits = 0, bbits = 0;
474
            for (int i = 0; i < width; i++) {
164✔
475
               vlog_logic_t bit = number_bit(num, width - i - 1);
144✔
476
               abits = (abits << 1) | (bit & 1);
144✔
477
               bbits = (bbits << 1) | ((bit >> 1) & 1);
144✔
478
            }
479

480
            mir_type_t t_vec4 = mir_vec4_type(mu, width, false);
20✔
481
            return mir_const_vec(mu, t_vec4, abits, bbits);
20✔
482
         }
483
      }
484
   case V_BINARY:
380✔
485
      return vlog_lower_binary(mu, v);
380✔
486
   case V_UNARY:
48✔
487
      return vlog_lower_unary(mu, v);
48✔
488
   case V_SYS_FCALL:
52✔
489
      return vlog_lower_sys_tfcall(mu, v);
52✔
490
   case V_BIT_SELECT:
16✔
491
      return vlog_lower_rvalue_bit_select(mu, v);
16✔
492
   case V_PART_SELECT:
12✔
493
      {
494
         mir_value_t base = vlog_lower_resolved(mu, vlog_value(v));
12✔
495

496
         vlog_node_t dt = vlog_type(vlog_ref(vlog_value(v)));
12✔
497

498
         mir_value_t off = vlog_lower_array_off(mu, dt, vlog_left(v));
12✔
499
         mir_value_t ptr = mir_build_array_ref(mu, base, off);
12✔
500

501
         int64_t left, right;
12✔
502
         vlog_bounds(v, &left, &right);
12✔
503

504
         int64_t size = left < right ? right - left + 1 : left - right + 1;
12✔
505

506
         mir_type_t t_vec = mir_vec4_type(mu, size, false);
12✔
507
         return mir_build_pack(mu, t_vec, ptr);
12✔
508
      }
509
   case V_CONCAT:
12✔
510
      {
511
         int size = 0, repeat = 1, pos = 0;
12✔
512
         const int nparams = vlog_params(v);
12✔
513
         mir_value_t *inputs LOCAL =
12✔
514
            xmalloc_array(nparams, sizeof(mir_value_t));
12✔
515

516
         for (int i = 0; i < nparams; i++) {
32✔
517
            inputs[i] = vlog_lower_rvalue(mu, vlog_param(v, i));
20✔
518
            assert(mir_is_vector(mu, inputs[i]));
20✔
519
            size += mir_get_size(mu, mir_get_type(mu, inputs[i]));
20✔
520
         }
521

522
         if (vlog_has_value(v))
12✔
523
            size *= (repeat = vlog_get_const(vlog_value(v)));
4✔
524

525
         mir_type_t type = mir_vec4_type(mu, size, false);
12✔
526
         mir_value_t result = mir_const_vec(mu, type, 0, 0);
12✔
527

528
         for (int i = 0; i < repeat; i++) {
52✔
529
            for (int j = nparams - 1; j >= 0; j--) {
88✔
530
               // TODO: add a vector-insert operation
531
               mir_value_t cast = mir_build_cast(mu, type, inputs[j]);
48✔
532
               mir_value_t amount = mir_const_vec(mu, type, pos, 0);
48✔
533
               mir_value_t shift =
48✔
534
                  mir_build_binary(mu, MIR_VEC_SLL, type, cast, amount);
48✔
535
               result = mir_build_binary(mu, MIR_VEC_BIT_OR, type,
48✔
536
                                         result, shift);
537
               pos += mir_get_size(mu, mir_get_type(mu, inputs[j]));
48✔
538
            }
539
         }
540

541
         return result;
12✔
542
      }
543
   case V_PREFIX:
4✔
544
      {
545
         vlog_node_t target = vlog_target(v);
4✔
546

547
         mir_value_t prev = vlog_lower_rvalue(mu, target);
4✔
548
         mir_type_t type = mir_get_type(mu, prev);
4✔
549
         mir_value_t one = mir_const_vec(mu, type, 1, 0);
4✔
550
         mir_value_t inc = mir_build_binary(mu, MIR_VEC_ADD, type, prev, one);
4✔
551

552
         // Must save/restore around blocking assignment
553
         mir_value_t tmp = mir_add_var(mu, type, MIR_NULL_STAMP,
4✔
554
                                       ident_uniq("prefix"), MIR_VAR_TEMP);
555
         mir_build_store(mu, tmp, inc);
4✔
556

557
         vlog_assign_variable(mu, target, inc);
4✔
558

559
         return mir_build_load(mu, tmp);
4✔
560
      }
UNCOV
561
   default:
×
562
      CANNOT_HANDLE(v);
2,272✔
563
   }
564
}
565

566
static mir_value_t vlog_lower_time(mir_unit_t *mu, vlog_node_t v)
48✔
567
{
568
   assert(vlog_kind(v) == V_NUMBER);
48✔
569

570
   mir_type_t t_time = mir_time_type(mu);
48✔
571
   number_t num = vlog_number(v);
48✔
572

573
   return mir_const(mu, t_time, number_integer(num));
48✔
574
}
575

576
static void vlog_lower_sensitivity(mir_unit_t *mu, vlog_node_t v)
224✔
577
{
578
   switch (vlog_kind(v)) {
352✔
579
   case V_REF:
160✔
580
      {
581
         switch (vlog_kind(vlog_ref(v))) {
160✔
582
         case V_PORT_DECL:
160✔
583
         case V_NET_DECL:
584
         case V_VAR_DECL:
585
            {
586
               mir_type_t t_offset = mir_offset_type(mu);
160✔
587

588
               vlog_lvalue_t lvalue = vlog_lower_lvalue(mu, v);
160✔
589
               mir_value_t count = mir_const(mu, t_offset, lvalue.size);
160✔
590

591
               mir_build_sched_event(mu, lvalue.nets, count);
160✔
592
            }
593
            break;
160✔
594
         case V_PARAM_DECL:
595
         case V_LOCALPARAM:
596
            break;
UNCOV
597
         default:
×
UNCOV
598
            CANNOT_HANDLE(v);
×
599
         }
600
      }
601
      break;
602
   case V_BIT_SELECT:
8✔
603
      {
604
         vlog_lower_sensitivity(mu, vlog_value(v));
8✔
605

606
         const int nparams = vlog_params(v);
8✔
607
         for (int i = 0; i < nparams; i++)
16✔
608
            vlog_lower_sensitivity(mu, vlog_param(v, i));
8✔
609
      }
610
      break;
611
   case V_EVENT:
116✔
612
      vlog_lower_sensitivity(mu, vlog_value(v));
116✔
613
      break;
116✔
614
   case V_NUMBER:
615
      break;
616
   case V_BINARY:
8✔
617
      vlog_lower_sensitivity(mu, vlog_left(v));
8✔
618
      vlog_lower_sensitivity(mu, vlog_right(v));
8✔
619
      break;
8✔
620
   case V_UNARY:
4✔
621
      vlog_lower_sensitivity(mu, vlog_value(v));
4✔
622
      break;
4✔
623
   case V_CONCAT:
4✔
624
      {
625
         const int nparams = vlog_params(v);
4✔
626
         for (int i = 0; i < nparams; i++)
8✔
627
            vlog_lower_sensitivity(mu, vlog_param(v, i));
4✔
628
      }
629
      break;
UNCOV
630
   default:
×
UNCOV
631
      CANNOT_HANDLE(v);
×
632
   }
633
}
224✔
634

635
static void vlog_lower_timing(mir_unit_t *mu, vlog_node_t v, bool is_static)
356✔
636
{
637
   mir_block_t true_bb = mir_add_block(mu), false_bb = MIR_NULL_BLOCK;
356✔
638

639
   vlog_node_t ctrl = vlog_value(v);
356✔
640
   switch (vlog_kind(ctrl)) {
356✔
641
   case V_DELAY_CONTROL:
256✔
642
      {
643
         mir_type_t t_time = mir_time_type(mu);
256✔
644
         mir_value_t delay = vlog_lower_rvalue(mu, vlog_value(ctrl));
256✔
645
         mir_value_t cast = mir_build_cast(mu, t_time, delay);
256✔
646

647
         mir_build_wait(mu, true_bb, cast);
256✔
648

649
         mir_set_cursor(mu, true_bb, MIR_APPEND);
256✔
650
      }
651
      break;
256✔
652
   case V_EVENT_CONTROL:
100✔
653
      {
654
         mir_value_t test = MIR_NULL_VALUE;
100✔
655
         const int nparams = vlog_params(ctrl);
100✔
656
         if (nparams > 0) {
100✔
657
            test = vlog_lower_rvalue(mu, vlog_param(ctrl, 0));
96✔
658
            for (int i = 1; i < nparams; i++) {
124✔
659
               mir_value_t sub = vlog_lower_rvalue(mu, vlog_param(ctrl, i));
28✔
660
               test = mir_build_or(mu, test, sub);
28✔
661
            }
662
         }
663

664
         false_bb = mir_add_block(mu);
100✔
665

666
         if (mir_is_null(test))
100✔
667
            mir_build_jump(mu, false_bb);
4✔
668
         else
669
            mir_build_cond(mu, test, true_bb, false_bb);
96✔
670

671
         mir_set_cursor(mu, true_bb, MIR_APPEND);
100✔
672
      }
673
      break;
100✔
UNCOV
674
   default:
×
UNCOV
675
      CANNOT_HANDLE(ctrl);
×
676
   }
677

678
   vlog_lower_stmts(mu, v);
356✔
679

680
   if (!mir_is_null(false_bb)) {
356✔
681
      if (!mir_block_finished(mu, mir_get_cursor(mu, NULL)))
100✔
682
         mir_build_jump(mu, false_bb);
100✔
683

684
      mir_set_cursor(mu, false_bb, MIR_APPEND);
100✔
685
   }
686
}
356✔
687

688
static void vlog_lower_blocking_assignment(mir_unit_t *mu, vlog_node_t v)
364✔
689
{
690
   if (vlog_has_delay(v)) {
364✔
691
      vlog_node_t delay = vlog_delay(v);
32✔
692
      assert(vlog_kind(delay) == V_DELAY_CONTROL);
32✔
693

694
      mir_block_t delay_bb = mir_add_block(mu);
32✔
695

696
      mir_build_wait(mu, delay_bb, vlog_lower_time(mu, vlog_value(delay)));
32✔
697

698
      mir_set_cursor(mu, delay_bb, MIR_APPEND);
32✔
699
   }
700

701
   mir_value_t value = vlog_lower_rvalue(mu, vlog_value(v));
364✔
702
   vlog_assign_variable(mu, vlog_target(v), value);
364✔
703
}
364✔
704

705
static void vlog_lower_non_blocking_assignment(mir_unit_t *mu, vlog_node_t v)
196✔
706
{
707
   vlog_node_t target = vlog_target(v);
196✔
708

709
   vlog_lvalue_t lvalue = vlog_lower_lvalue(mu, target);
196✔
710
   mir_value_t value = vlog_lower_rvalue(mu, vlog_value(v));
196✔
711
   assert(mir_is_vector(mu, value));
196✔
712

713
   mir_type_t t_offset = mir_offset_type(mu);
196✔
714
   mir_type_t t_vec = mir_vec4_type(mu, lvalue.size, false);
196✔
715

716
   mir_value_t resize = mir_build_cast(mu, t_vec, value);
196✔
717
   mir_value_t count = mir_const(mu, t_offset, lvalue.size);
196✔
718

719
   mir_value_t tmp = MIR_NULL_VALUE;
196✔
720
   if (lvalue.size > 1)
196✔
721
      tmp = vlog_get_temp(mu, lvalue.base);
56✔
722

723
   const uint8_t strength = vlog_is_net(target) ? ST_STRONG : 0;
196✔
724
   mir_value_t unpacked = mir_build_unpack(mu, resize, strength, tmp);
196✔
725

726
   mir_type_t t_time = mir_time_type(mu);
196✔
727
   mir_value_t reject = mir_const(mu, t_time, 0);
196✔
728

729
   mir_value_t after;
196✔
730
   if (vlog_has_delay(v)) {
196✔
731
      vlog_node_t delay = vlog_delay(v);
16✔
732
      assert(vlog_kind(delay) == V_DELAY_CONTROL);
16✔
733

734
      after = vlog_lower_time(mu, vlog_value(delay));
16✔
735
   }
736
   else
737
      after = mir_const(mu, t_time, 0);
180✔
738

739
   mir_build_sched_waveform(mu, lvalue.nets, count, unpacked,
196✔
740
                            reject, after);
741
}
196✔
742

743
static void vlog_lower_if(mir_unit_t *mu, vlog_node_t v)
224✔
744
{
745
   mir_block_t exit_bb = MIR_NULL_BLOCK;
224✔
746

747
   const int nconds = vlog_conds(v);
224✔
748
   for (int i = 0; i < nconds; i++) {
452✔
749
      vlog_node_t c = vlog_cond(v, i);
292✔
750
      mir_block_t next_bb = MIR_NULL_BLOCK;
292✔
751

752
      if (vlog_has_value(c)) {
292✔
753
         mir_value_t test = vlog_lower_rvalue(mu, vlog_value(c));
228✔
754
         assert(mir_is_vector(mu, test));
228✔
755

756
         mir_value_t zero = mir_const_vec(mu, mir_get_type(mu, test), 0, 0);
228✔
757
         mir_value_t cmp = mir_build_cmp(mu, MIR_CMP_NEQ, test, zero);
228✔
758

759
         mir_block_t btrue = mir_add_block(mu);
228✔
760

761
         if (i == nconds - 1) {
228✔
762
            if (mir_is_null(exit_bb))
160✔
763
               exit_bb = mir_add_block(mu);
160✔
764
            next_bb = exit_bb;
160✔
765
         }
766
         else
767
            next_bb = mir_add_block(mu);
68✔
768

769
         mir_build_cond(mu, cmp, btrue, next_bb);
228✔
770

771
         mir_set_cursor(mu, btrue, MIR_APPEND);
228✔
772
      }
773

774
      vlog_lower_stmts(mu, c);
292✔
775

776
      if (!mir_block_finished(mu, MIR_NULL_BLOCK)) {
292✔
777
         if (mir_is_null(exit_bb))
292✔
778
            exit_bb = mir_add_block(mu);
64✔
779
         mir_build_jump(mu, exit_bb);
292✔
780
      }
781

782
      if (mir_is_null(next_bb))
292✔
783
         break;
784

785
      mir_set_cursor(mu, next_bb, MIR_APPEND);
228✔
786
   }
787

788
   if (!mir_is_null(exit_bb))
224✔
789
      mir_set_cursor(mu, exit_bb, MIR_APPEND);
224✔
790
}
224✔
791

792
static void vlog_lower_forever(mir_unit_t *mu, vlog_node_t v)
4✔
793
{
794
   mir_block_t body_bb = mir_add_block(mu);
4✔
795
   mir_build_jump(mu, body_bb);
4✔
796

797
   mir_set_cursor(mu, body_bb, MIR_APPEND);
4✔
798

799
   vlog_lower_stmts(mu, v);
4✔
800

801
   mir_build_jump(mu, body_bb);
4✔
802
}
4✔
803

804
static void vlog_lower_for_loop(mir_unit_t *mu, vlog_node_t v)
4✔
805
{
806
   mir_comment(mu, "Begin for loop");
4✔
807

808
   vlog_node_t init = vlog_left(v);
4✔
809
   assert(vlog_kind(init) == V_FOR_INIT);
4✔
810

811
   assert(vlog_decls(init) == 0);   // TODO
4✔
812

813
   vlog_lower_stmts(mu, init);
4✔
814

815
   mir_block_t body_bb = mir_add_block(mu);
4✔
816
   mir_block_t step_bb = mir_add_block(mu);
4✔
817
   mir_block_t test_bb = mir_add_block(mu);
4✔
818
   mir_block_t exit_bb = mir_add_block(mu);
4✔
819

820
   mir_build_jump(mu, test_bb);
4✔
821

822
   mir_set_cursor(mu, test_bb, MIR_APPEND);
4✔
823

824
   mir_comment(mu, "For loop test");
4✔
825

826
   mir_value_t test = vlog_lower_rvalue(mu, vlog_value(v));
4✔
827
   assert(mir_is_vector(mu, test));
4✔
828

829
   mir_value_t zero = mir_const_vec(mu, mir_get_type(mu, test), 0, 0);
4✔
830
   mir_value_t cmp = mir_build_cmp(mu, MIR_CMP_NEQ, test, zero);
4✔
831
   mir_build_cond(mu, cmp, body_bb, exit_bb);
4✔
832

833
   mir_set_cursor(mu, body_bb, MIR_APPEND);
4✔
834

835
   mir_comment(mu, "For loop body");
4✔
836

837
   vlog_lower_stmts(mu, v);
4✔
838

839
   if (!mir_block_finished(mu, MIR_NULL_BLOCK))
4✔
840
      mir_build_jump(mu, step_bb);
4✔
841

842
   mir_set_cursor(mu, step_bb, MIR_APPEND);
4✔
843

844
   mir_comment(mu, "For loop step");
4✔
845

846
   vlog_node_t step = vlog_right(v);
4✔
847
   assert(vlog_kind(step) == V_FOR_STEP);
4✔
848

849
   vlog_lower_stmts(mu, step);
4✔
850

851
   mir_build_jump(mu, test_bb);
4✔
852

853
   mir_set_cursor(mu, exit_bb, MIR_APPEND);
4✔
854

855
   mir_comment(mu, "End for loop");
4✔
856
}
4✔
857

858
static void vlog_lower_case(mir_unit_t *mu, vlog_node_t v)
4✔
859
{
860
   mir_comment(mu, "Begin case statement");
4✔
861

862
   mir_value_t value = vlog_lower_rvalue(mu, vlog_value(v));
4✔
863
   mir_type_t type = mir_get_type(mu, value);
4✔
864

865
   // TODO: use a parallel case for small integer types
866

867
   const int nitems = vlog_stmts(v);
4✔
868
   mir_block_t *blocks LOCAL = xmalloc_array(nitems, sizeof(mir_block_t));
8✔
869

870
   mir_value_t zero = mir_const_vec(mu, mir_vec4_type(mu, 1, false), 0, 0);
4✔
871

872
   for (int i = 0; i < nitems; i++) {
36✔
873
      vlog_node_t item = vlog_stmt(v, i);
32✔
874
      assert(vlog_kind(item) == V_CASE_ITEM);
32✔
875

876
      blocks[i] = mir_add_block(mu);
32✔
877

878
      mir_block_t else_bb = mir_add_block(mu);
32✔
879

880
      mir_value_t comb = MIR_NULL_VALUE;
32✔
881
      const int nparams = vlog_params(item);
32✔
882
      for (int j = 0; j < nparams; j++) {
64✔
883
         mir_value_t test = vlog_lower_rvalue(mu, vlog_param(item, j));
32✔
884
         mir_value_t cast = mir_build_cast(mu, type, test);
32✔
885
         mir_value_t case_eq =
32✔
886
            mir_build_binary(mu, MIR_VEC_CASE_EQ, type, cast, value);
32✔
887
         mir_value_t cmp = mir_build_cmp(mu, MIR_CMP_NEQ, case_eq, zero);
32✔
888

889
         if (mir_is_null(comb))
32✔
890
            comb = cmp;
32✔
891
         else
UNCOV
892
            comb = mir_build_or(mu, comb, cmp);
×
893
      }
894

895
      if (mir_is_null(comb))
32✔
UNCOV
896
         mir_build_jump(mu, blocks[i]);
×
897
      else
898
         mir_build_cond(mu, comb, blocks[i], else_bb);
32✔
899

900
      mir_set_cursor(mu, else_bb, MIR_APPEND);
32✔
901
   }
902

903
   mir_block_t exit_bb = mir_get_cursor(mu, NULL);
4✔
904

905
   for (int i = 0; i < nitems; i++) {
36✔
906
      vlog_node_t item = vlog_stmt(v, i);
32✔
907
      assert(vlog_kind(item) == V_CASE_ITEM);
32✔
908

909
      mir_set_cursor(mu, blocks[i], MIR_APPEND);
32✔
910
      vlog_lower_stmts(mu, item);
32✔
911

912
      if (!mir_block_finished(mu, MIR_NULL_BLOCK))
32✔
913
         mir_build_jump(mu, exit_bb);
32✔
914
   }
915

916
   mir_set_cursor(mu, exit_bb, MIR_APPEND);
4✔
917

918
   mir_comment(mu, "End case statement");
4✔
919
}
4✔
920

921
static void vlog_lower_stmts(mir_unit_t *mu, vlog_node_t v)
1,176✔
922
{
923
   const int nstmts = vlog_stmts(v);
1,176✔
924
   for (int i = 0; i < nstmts; i++) {
3,200✔
925
      vlog_node_t s = vlog_stmt(v, i);
2,024✔
926
      mir_set_loc(mu, vlog_loc(s));
2,024✔
927

928
      switch (vlog_kind(s)) {
2,024✔
929
      case V_TIMING:
264✔
930
         vlog_lower_timing(mu, s, false);
264✔
931
         break;
264✔
932
      case V_BASSIGN:
364✔
933
         vlog_lower_blocking_assignment(mu, s);
364✔
934
         break;
364✔
935
      case V_NBASSIGN:
116✔
936
         vlog_lower_non_blocking_assignment(mu, s);
116✔
937
         break;
116✔
938
      case V_BLOCK:
340✔
939
         vlog_lower_stmts(mu, s);
340✔
940
         break;
340✔
941
      case V_SYS_TCALL:
704✔
942
         vlog_lower_sys_tfcall(mu, s);
704✔
943
         break;
704✔
944
      case V_IF:
224✔
945
         vlog_lower_if(mu, s);
224✔
946
         break;
224✔
947
      case V_FOREVER:
4✔
948
         vlog_lower_forever(mu, s);
4✔
949
         break;
4✔
950
      case V_FOR_LOOP:
4✔
951
         vlog_lower_for_loop(mu, s);
4✔
952
         break;
4✔
953
      case V_CASE:
4✔
954
         vlog_lower_case(mu, s);
4✔
955
         break;
4✔
UNCOV
956
      default:
×
957
         CANNOT_HANDLE(s);
2,024✔
958
      }
959
   }
960
}
1,176✔
961

962
static void vlog_lower_driver(mir_unit_t *mu, vlog_node_t v)
240✔
963
{
964
   mir_type_t t_offset = mir_offset_type(mu);
240✔
965

966
   vlog_node_t prefix = vlog_longest_static_prefix(v);
240✔
967

968
   vlog_lvalue_t target = vlog_lower_lvalue(mu, prefix);
240✔
969
   mir_value_t one = mir_const(mu, t_offset, target.size);
240✔
970

971
   mir_build_drive_signal(mu, target.nets, one);
240✔
972
}
240✔
973

974
static void vlog_driver_cb(vlog_node_t v, void *context)
7,020✔
975
{
976
   mir_unit_t *mu = context;
7,020✔
977

978
   switch (vlog_kind(v)) {
7,020✔
979
   case V_NBASSIGN:
196✔
980
   case V_ASSIGN:
981
      vlog_lower_driver(mu, vlog_target(v));
196✔
982
      break;
196✔
983
   default:
984
      break;
985
   }
986
}
7,020✔
987

988
static void vlog_lower_always(mir_unit_t *mu, vlog_node_t v)
104✔
989
{
990
   mir_block_t start_bb = mir_add_block(mu);
104✔
991
   assert(start_bb.id == 1);
104✔
992

993
   vlog_visit(v, vlog_driver_cb, mu);
104✔
994

995
   vlog_node_t timing = NULL, s0 = vlog_stmt(v, 0);
104✔
996
   if (vlog_kind(s0) == V_TIMING) {
104✔
997
      timing = s0;
92✔
998

999
      vlog_node_t ctrl = vlog_value(timing);
92✔
1000
      assert(vlog_kind(ctrl) == V_EVENT_CONTROL);
92✔
1001

1002
      const int nparams = vlog_params(ctrl);
92✔
1003
      for (int i = 0; i < nparams; i++)
208✔
1004
         vlog_lower_sensitivity(mu, vlog_param(ctrl, i));
116✔
1005
   }
1006

1007
   mir_build_return(mu, MIR_NULL_VALUE);
104✔
1008

1009
   mir_set_cursor(mu, start_bb, MIR_APPEND);
104✔
1010

1011
   if (timing != NULL)
104✔
1012
      vlog_lower_timing(mu, timing, true);
92✔
1013
   else
1014
      vlog_lower_stmts(mu, v);
12✔
1015

1016
   mir_build_wait(mu, start_bb, MIR_NULL_VALUE);
104✔
1017
}
104✔
1018

1019
static void vlog_lower_initial(mir_unit_t *mu, vlog_node_t v)
128✔
1020
{
1021
   mir_block_t start_bb = mir_add_block(mu);
128✔
1022
   assert(start_bb.id == 1);
128✔
1023

1024
   vlog_visit(v, vlog_driver_cb, mu);
128✔
1025

1026
   mir_build_return(mu, MIR_NULL_VALUE);
128✔
1027

1028
   mir_set_cursor(mu, start_bb, MIR_APPEND);
128✔
1029

1030
   vlog_lower_stmts(mu, v);
128✔
1031

1032
   if (!mir_block_finished(mu, MIR_NULL_BLOCK))
128✔
1033
      mir_build_return(mu, MIR_NULL_VALUE);
124✔
1034
}
128✔
1035

1036
static void vlog_lower_continuous_assign(mir_unit_t *mu,vlog_node_t v)
80✔
1037
{
1038
   mir_block_t start_bb = mir_add_block(mu);
80✔
1039
   assert(start_bb.id == 1);
80✔
1040

1041
   vlog_visit(v, vlog_driver_cb, mu);
80✔
1042

1043
   vlog_lower_sensitivity(mu, vlog_value(v));
80✔
1044

1045
   mir_build_return(mu, MIR_NULL_VALUE);
80✔
1046

1047
   mir_set_cursor(mu, start_bb, MIR_APPEND);
80✔
1048

1049
   vlog_lower_non_blocking_assignment(mu, v);
80✔
1050

1051
   mir_build_wait(mu, start_bb, MIR_NULL_VALUE);
80✔
1052
}
80✔
1053

1054
static void vlog_lower_gate_inst(mir_unit_t *mu, vlog_node_t v)
44✔
1055
{
1056
   mir_block_t start_bb = mir_add_block(mu);
44✔
1057
   assert(start_bb.id == 1);
44✔
1058

1059
   vlog_lower_driver(mu, vlog_target(v));
44✔
1060

1061
   mir_type_t t_offset = mir_offset_type(mu);
44✔
1062
   mir_type_t t_time = mir_time_type(mu);
44✔
1063
   mir_type_t t_logic = mir_vec4_type(mu, 1, false);
44✔
1064

1065
   const int nparams = vlog_params(v);
44✔
1066
   int first_term = 0;
44✔
1067
   for (int i = 0; i < nparams; i++) {
104✔
1068
      vlog_node_t p = vlog_param(v, i);
60✔
1069
      if (vlog_kind(p) == V_STRENGTH)
60✔
1070
         first_term = i + 1;
24✔
1071
      else {
1072
         vlog_lvalue_t lvalue = vlog_lower_lvalue(mu, p);
36✔
1073
         mir_value_t count = mir_const(mu, t_offset, lvalue.size);
36✔
1074
         mir_build_sched_event(mu, lvalue.nets, count);
36✔
1075
      }
1076
   }
1077

1078
   mir_build_return(mu, MIR_NULL_VALUE);
44✔
1079

1080
   mir_set_cursor(mu, start_bb, MIR_APPEND);
44✔
1081

1082
   bool negate = false;
44✔
1083
   uint8_t strength = ST_STRONG;
44✔
1084
   mir_value_t value = MIR_NULL_VALUE;
44✔
1085
   const vlog_gate_kind_t kind = vlog_subkind(v);
44✔
1086
   switch (kind) {
44✔
1087
   case V_GATE_PULLUP:
24✔
1088
   case V_GATE_PULLDOWN:
1089
      strength = vlog_subkind(vlog_param(v, 0));
24✔
1090
      value = mir_const_vec(mu, t_logic, kind == V_GATE_PULLUP, 0);
24✔
1091
      break;
24✔
1092

1093
   case V_GATE_NAND:
4✔
1094
   case V_GATE_NOR:
1095
   case V_GATE_XNOR:
1096
      negate = true;
4✔
1097
   case V_GATE_AND:
16✔
1098
   case V_GATE_OR:
1099
   case V_GATE_XOR:
1100
      {
1101
         static const mir_vec_op_t op_map[] = {
16✔
1102
            [V_GATE_AND] = MIR_VEC_BIT_AND,
1103
            [V_GATE_NAND] = MIR_VEC_BIT_AND,
1104
            [V_GATE_OR] = MIR_VEC_BIT_OR,
1105
            [V_GATE_NOR] = MIR_VEC_BIT_OR,
1106
            [V_GATE_XOR] = MIR_VEC_BIT_XOR,
1107
            [V_GATE_XNOR] = MIR_VEC_BIT_XOR,
1108
         };
1109

1110
         value = vlog_lower_rvalue(mu, vlog_param(v, first_term));
16✔
1111

1112
         const int nelems = nparams - first_term;
16✔
1113
         for (int i = 1; i < nelems; i++) {
32✔
1114
            vlog_node_t p = vlog_param(v, first_term + i);
16✔
1115
            mir_value_t arg = vlog_lower_rvalue(mu, p);
16✔
1116
            value = mir_build_binary(mu, op_map[kind], t_logic, value, arg);
16✔
1117
         }
1118

1119
         if (negate)
16✔
1120
            value = mir_build_unary(mu, MIR_VEC_BIT_NOT, t_logic, value);
4✔
1121
      }
1122
      break;
1123

1124
   case V_GATE_NOT:
4✔
1125
      {
1126
         const int nparams = vlog_params(v);
4✔
1127
         mir_value_t input = vlog_lower_rvalue(mu, vlog_param(v, nparams - 1));
4✔
1128
         value = mir_build_unary(mu, MIR_VEC_BIT_NOT, t_logic, input);
4✔
1129
      }
1130
      break;
4✔
1131

UNCOV
1132
   default:
×
UNCOV
1133
      CANNOT_HANDLE(v);
×
1134
   }
1135

1136
   mir_value_t unpacked = mir_build_unpack(mu, value, strength, MIR_NULL_VALUE);
44✔
1137

1138
   mir_value_t reject = mir_const(mu, t_time, 0);
44✔
1139
   mir_value_t after = mir_const(mu, t_time, 0);
44✔
1140

1141
   vlog_lvalue_t lvalue = vlog_lower_lvalue(mu, vlog_target(v));
44✔
1142
   mir_value_t count = mir_const(mu, t_offset, lvalue.size);
44✔
1143

1144
   mir_build_sched_waveform(mu, lvalue.nets, count, unpacked, reject, after);
44✔
1145
   mir_build_wait(mu, start_bb, MIR_NULL_VALUE);
44✔
1146
}
44✔
1147

1148
void vlog_lower_deferred(mir_unit_t *mu, object_t *obj)
356✔
1149
{
1150
   vlog_node_t v = vlog_from_object(obj);
356✔
1151
   assert(v != NULL);
356✔
1152

1153
   switch (vlog_kind(v)) {
356✔
1154
   case V_ALWAYS:
104✔
1155
      vlog_lower_always(mu, v);
104✔
1156
      break;
104✔
1157
   case V_INITIAL:
128✔
1158
      vlog_lower_initial(mu, v);
128✔
1159
      break;
128✔
1160
   case V_ASSIGN:
80✔
1161
      vlog_lower_continuous_assign(mu, v);
80✔
1162
      break;
80✔
1163
   case V_GATE_INST:
44✔
1164
      vlog_lower_gate_inst(mu, v);
44✔
1165
      break;
44✔
UNCOV
1166
   default:
×
UNCOV
1167
      CANNOT_HANDLE(v);
×
1168
   }
1169
}
356✔
1170
static void vlog_lower_net_decl(mir_unit_t *mu, vlog_node_t v, tree_t wrap,
231✔
1171
                                mir_value_t resfn)
1172
{
1173
   mir_type_t t_net_value = mir_int_type(mu, 0, 255);
231✔
1174
   mir_type_t t_net_signal = mir_signal_type(mu, t_net_value);
231✔
1175
   mir_type_t t_offset = mir_offset_type(mu);
231✔
1176

1177
   assert(!vlog_has_value(v));   // Should have been replaced with assign
231✔
1178

1179
   mir_value_t value = mir_const(mu, t_net_value, LOGIC_X);
231✔
1180
   mir_value_t count = mir_const(mu, t_offset, vlog_size(vlog_type(v)));
231✔
1181
   mir_value_t size = mir_const(mu, t_offset, 1);
231✔
1182
   mir_value_t flags = mir_const(mu, t_offset, 0);
231✔
1183
   mir_value_t locus = mir_build_locus(mu, tree_to_object(wrap));
231✔
1184

1185
   mir_value_t signal = mir_build_init_signal(mu, t_net_value, count, size,
231✔
1186
                                              value, flags, locus,
1187
                                              MIR_NULL_VALUE);
231✔
1188

1189
   mir_build_resolve_signal(mu, signal, resfn);
231✔
1190

1191
   mir_value_t var = mir_add_var(mu, t_net_signal, MIR_NULL_STAMP,
231✔
1192
                                 vlog_ident(v), MIR_VAR_SIGNAL);
1193
   mir_build_store(mu, var, signal);
231✔
1194

1195
   mir_put_object(mu, v, var);
231✔
1196
}
231✔
1197

1198
static void vlog_lower_var_decl(mir_unit_t *mu, vlog_node_t v, tree_t wrap)
252✔
1199
{
1200
   mir_type_t t_logic = mir_int_type(mu, 0, 3);
252✔
1201
   mir_type_t t_logic_signal = mir_signal_type(mu, t_logic);
252✔
1202
   mir_type_t t_offset = mir_offset_type(mu);
252✔
1203

1204
   type_info_t *ti = vlog_type_info(mu, vlog_type(v));
252✔
1205

1206
   mir_value_t value;
252✔
1207
   if (vlog_has_value(v)) {
252✔
1208
      mir_value_t tmp = MIR_NULL_VALUE;
8✔
1209
      if (ti->size > 1)
8✔
1210
         tmp = vlog_get_temp(mu, ti);
4✔
1211

1212
      mir_value_t packed = vlog_lower_rvalue(mu, vlog_value(v));
8✔
1213
      mir_value_t cast = mir_build_cast(mu, ti->type, packed);
8✔
1214
      value = mir_build_unpack(mu, cast, 0, tmp);
8✔
1215
   }
1216
   else
1217
      value = mir_const(mu, t_logic, LOGIC_X);
244✔
1218

1219
   mir_value_t count = mir_const(mu, t_offset, ti->size);
252✔
1220
   mir_value_t size = mir_const(mu, t_offset, 1);
252✔
1221
   mir_value_t flags = mir_const(mu, t_offset, 0);
252✔
1222
   mir_value_t locus = mir_build_locus(mu, tree_to_object(wrap));
252✔
1223

1224
   mir_value_t signal = mir_build_init_signal(mu, t_logic, count, size, value,
252✔
1225
                                              flags, locus, MIR_NULL_VALUE);
252✔
1226

1227
   mir_value_t var = mir_add_var(mu, t_logic_signal, MIR_NULL_STAMP,
252✔
1228
                                 vlog_ident(v), MIR_VAR_SIGNAL);
1229
   mir_build_store(mu, var, signal);
252✔
1230

1231
   mir_put_object(mu, v, var);
252✔
1232
}
252✔
1233

1234
static mir_type_t vlog_lower_vhdl_type(mir_unit_t *mu, type_t type)
116✔
1235
{
1236
   if (type_eq(type, ieee_type(IEEE_STD_ULOGIC)))
116✔
1237
      return mir_int_type(mu, 0, 8);
24✔
1238
   else if (type_eq(type, ieee_type(IEEE_STD_ULOGIC_VECTOR)))
92✔
1239
      return mir_uarray_type(mu, 1, mir_int_type(mu, 0, 8));
4✔
1240
   else if (type_eq(type, verilog_type(VERILOG_NET_VALUE)))
88✔
1241
      return mir_int_type(mu, 0, 255);
84✔
1242
   else if (type_eq(type, verilog_type(VERILOG_LOGIC)))
4✔
UNCOV
1243
      return mir_int_type(mu, 0, 3);
×
1244
   else if (type_eq(type, verilog_type(VERILOG_WIRE_ARRAY)))
4✔
1245
      return mir_uarray_type(mu, 1, mir_int_type(mu, 0, 3));
4✔
1246

1247
   fatal_trace("cannot lower VHDL type %s", type_pp(type));
1248
}
1249

1250
static void vlog_lower_converter(mir_unit_t *mu, tree_t cf, mir_value_t in,
116✔
1251
                                 mir_value_t out)
1252
{
1253
   tree_t decl = tree_ref(cf);
116✔
1254
   assert(tree_kind(decl) == T_FUNC_DECL);
116✔
1255

1256
   type_t rtype = type_result(tree_type(decl));
116✔
1257

1258
   // Dummy return value to force function calling convention
1259
   mir_type_t t_offset = mir_offset_type(mu);
116✔
1260
   mir_set_result(mu, t_offset);
116✔
1261

1262
   mir_type_t t_context = mir_context_type(mu, mir_get_parent(mu));
116✔
1263
   mir_add_param(mu, t_context, MIR_NULL_STAMP, ident_new("context"));
116✔
1264

1265
   mir_type_t t_conv = mir_conversion_type(mu);
116✔
1266
   mir_value_t conv =
116✔
1267
      mir_add_param(mu, t_conv, MIR_NULL_STAMP, ident_new("cf"));
116✔
1268

1269
   mir_type_t t_out = vlog_lower_vhdl_type(mu, rtype);
116✔
1270

1271
   ident_t func = tree_ident2(tree_ref(cf));
116✔
1272

1273
   mir_value_t pkg = mir_build_link_package(mu, well_known(W_NVC_VERILOG));
116✔
1274

1275
   mir_value_t resolved = mir_build_resolved(mu, in);
116✔
1276

1277
   mir_value_t arg, count;
116✔
1278
   if (type_is_array(rtype)) {
116✔
1279
      int64_t length;
8✔
1280
      if (!folded_length(range_of(tree_type(tree_value(cf)), 0), &length))
8✔
1281
         should_not_reach_here();
1282

1283
      count = mir_const(mu, t_offset, length);
8✔
1284

1285
      mir_dim_t dims[] = {
8✔
1286
         { .left  = mir_const(mu, t_offset, 1),
8✔
1287
           .right = count,
1288
           .dir   = mir_const(mu, mir_bool_type(mu), RANGE_TO),
8✔
1289
         }
1290
      };
1291
      arg = mir_build_wrap(mu, resolved, dims, 1);
8✔
1292
   }
1293
   else {
1294
      arg = mir_build_load(mu, resolved);
108✔
1295
      count = mir_const(mu, t_offset, 1);
108✔
1296
   }
1297

1298
   mir_value_t args[] = { pkg, arg };
116✔
1299

1300
   mir_value_t result = mir_build_fcall(mu, func, t_out, MIR_NULL_STAMP,
116✔
1301
                                        args, ARRAY_LEN(args));
1302

1303
   if (mir_is(mu, result, MIR_TYPE_UARRAY))
116✔
1304
      result = mir_build_unwrap(mu, result);
8✔
1305

1306
   if (mir_is(mu, out, MIR_TYPE_UARRAY))
116✔
1307
      out = mir_build_unwrap(mu, out);
4✔
1308

1309
   mir_build_put_conversion(mu, conv, out, count, result);
116✔
1310

1311
   mir_build_return(mu, mir_const(mu, t_offset, 0));
116✔
1312
}
116✔
1313

1314
static void vlog_lower_convert_in(mir_unit_t *mu, object_t *obj)
80✔
1315
{
1316
   tree_t map = tree_from_object(obj);
80✔
1317
   assert(tree_kind(map) == T_PARAM);
80✔
1318

1319
   tree_t cf = tree_value(map);
80✔
1320
   assert(tree_kind(cf) == T_CONV_FUNC);
80✔
1321

1322
   mir_context_t *mc = mir_get_context(mu);
80✔
1323

1324
   ident_t parent1 = mir_get_parent(mu);
80✔
1325
   mir_shape_t *shape1 = mir_get_shape(mc, parent1);
80✔
1326

1327
   ident_t parent2 = mir_get_shape_parent(shape1);
80✔
1328
   mir_shape_t *shape2 = mir_get_shape(mc, parent2);
80✔
1329

1330
   tree_t arg = tree_value(cf);
80✔
1331
   assert(tree_kind(arg) == T_REF);
80✔
1332

1333
   int nth = mir_find_slot(shape2, tree_ident(tree_ref(arg)));
80✔
1334
   assert(nth >= 0);
80✔
1335

1336
   mir_value_t in_upref = mir_build_var_upref(mu, 2, nth);
80✔
1337
   mir_value_t in_nets = mir_build_load(mu, in_upref);
80✔
1338

1339
   int hops;
80✔
1340
   mir_value_t var = mir_search_object(mu, map, &hops);
80✔
1341
   assert(!mir_is_null(var));
80✔
1342
   assert(hops == 1);
80✔
1343

1344
   mir_value_t out_upref = mir_build_var_upref(mu, hops, var.id);
80✔
1345
   mir_value_t out_nets = mir_build_load(mu, out_upref);
80✔
1346

1347
   vlog_lower_converter(mu, cf, in_nets, out_nets);
80✔
1348
}
80✔
1349

1350
static void vlog_lower_convert_out(mir_unit_t *mu, object_t *obj)
36✔
1351
{
1352
   tree_t map = tree_from_object(obj);
36✔
1353
   assert(tree_kind(map) == T_PARAM);
36✔
1354

1355
   tree_t cf = tree_name(map);
36✔
1356
   assert(tree_kind(cf) == T_CONV_FUNC);
36✔
1357

1358
   mir_context_t *mc = mir_get_context(mu);
36✔
1359

1360
   ident_t parent1 = mir_get_parent(mu);
36✔
1361
   mir_shape_t *shape1 = mir_get_shape(mc, parent1);
36✔
1362

1363
   ident_t parent2 = mir_get_shape_parent(shape1);
36✔
1364
   mir_shape_t *shape2 = mir_get_shape(mc, parent2);
36✔
1365

1366
   int hops;
36✔
1367
   mir_value_t var = mir_search_object(mu, map, &hops);
36✔
1368
   assert(!mir_is_null(var));
36✔
1369
   assert(hops == 1);
36✔
1370

1371
   mir_value_t in_upref = mir_build_var_upref(mu, hops, var.id);
36✔
1372
   mir_value_t in_nets = mir_build_load(mu, in_upref);
36✔
1373

1374
   tree_t dst = tree_value(map);
36✔
1375
   assert(tree_kind(dst) == T_REF);
36✔
1376

1377
   int nth = mir_find_slot(shape2, tree_ident(tree_ref(dst)));
36✔
1378
   assert(nth >= 0);
36✔
1379

1380
   mir_value_t out_upref = mir_build_var_upref(mu, 2, nth);
36✔
1381
   mir_value_t out_nets = mir_build_load(mu, out_upref);
36✔
1382

1383
   vlog_lower_converter(mu, cf, in_nets, out_nets);
36✔
1384
}
36✔
1385

1386
void vlog_lower_block(mir_context_t *mc, ident_t parent, tree_t b)
179✔
1387
{
1388
   tree_t hier = tree_decl(b, 0);
179✔
1389
   assert(tree_kind(hier) == T_HIER);
179✔
1390

1391
   mir_shape_t *shape = mir_get_shape(mc, parent);
179✔
1392
   ident_t qual = tree_ident2(hier);
179✔
1393
   mir_unit_t *mu = mir_unit_new(mc, qual, tree_to_object(b),
179✔
1394
                                 MIR_UNIT_INSTANCE, shape);
1395

1396
   tree_t wrap = tree_ref(hier);
179✔
1397
   assert(tree_kind(wrap) == T_VERILOG);
179✔
1398

1399
   vlog_node_t body = tree_vlog(wrap);
179✔
1400
   assert(vlog_kind(body) == V_INST_BODY);
179✔
1401

1402
   hash_t *map = hash_new(16);
179✔
1403

1404
   const int vhdl_ndecls = tree_decls(b);
179✔
1405
   const int vlog_ndecls = vlog_decls(body);
179✔
1406

1407
   for (int i = 1, pos = 0; i < vhdl_ndecls; i++) {
543✔
1408
      tree_t t = tree_decl(b, i);
364✔
1409
      ident_t id = tree_ident(t);
364✔
1410
      for (; pos < vlog_ndecls; pos++) {
1,036✔
1411
         vlog_node_t v = vlog_decl(body, pos);
672✔
1412
         if (vlog_ident(v) == id) {
672✔
1413
            hash_put(map, v, t);
364✔
1414
            break;
364✔
1415
         }
1416
      }
1417

1418
      if (pos == vlog_ndecls)
364✔
1419
         fatal_trace("missing VHDL signal for %s", istr(id));
1420
   }
1421

1422
   const int nports = vlog_ports(body);
179✔
1423
   assert(tree_ports(b) == nports);
179✔
1424
   assert(tree_params(b) == nports);
179✔
1425

1426
   for (int i = 0; i < nports; i++)
324✔
1427
      hash_put(map, vlog_ref(vlog_ref(vlog_port(body, i))), tree_port(b, i));
145✔
1428

1429
   ident_t pkg_name = well_known(W_NVC_VERILOG);
179✔
1430
   mir_value_t pkg = mir_build_package_init(mu, pkg_name, MIR_NULL_VALUE);
179✔
1431

1432
   mir_type_t t_net_value = mir_int_type(mu, 0, 255);
179✔
1433
   mir_type_t t_resolution = mir_resolution_type(mu, t_net_value);
179✔
1434

1435
   ident_t var_name = ident_new("NVC.VERILOG.T_WIRE$resolution");
179✔
1436
   mir_value_t resfn =
179✔
1437
      mir_build_link_var(mu, pkg_name, pkg, var_name, t_resolution);
179✔
1438

1439
   for (int i = 0; i < vlog_ndecls; i++) {
833✔
1440
      vlog_node_t d = vlog_decl(body, i);
654✔
1441

1442
      switch (vlog_kind(d)) {
654✔
1443
      case V_PORT_DECL:
1444
         break;   // Translated below
1445
      case V_NET_DECL:
231✔
1446
         vlog_lower_net_decl(mu, d, hash_get(map, d), resfn);
231✔
1447
         break;
231✔
1448
      case V_VAR_DECL:
252✔
1449
         vlog_lower_var_decl(mu, d, hash_get(map, d));
252✔
1450
         break;
252✔
1451
      case V_LOCALPARAM:
1452
         break;  // Always inlined for now
UNCOV
1453
      default:
×
1454
         CANNOT_HANDLE(d);
654✔
1455
      }
1456
   }
1457

1458
   mir_value_t self = mir_build_context_upref(mu, 0);
179✔
1459
   mir_type_t t_self = mir_context_type(mu, qual);
179✔
1460
   mir_type_t t_offset = mir_offset_type(mu);
179✔
1461

1462
   for (int i = 0; i < nports; i++) {
324✔
1463
      vlog_node_t ref = vlog_port(body, i);
145✔
1464
      assert(vlog_kind(ref) == V_REF);
145✔
1465

1466
      vlog_node_t port = vlog_ref(ref);
145✔
1467
      assert(vlog_kind(port) == V_PORT_DECL);
145✔
1468

1469
      int hops;
145✔
1470
      mir_value_t var = mir_search_object(mu, vlog_ref(port), &hops);
145✔
1471
      assert(!mir_is_null(var));
145✔
1472
      assert(hops == 0);
145✔
1473

1474
      mir_put_object(mu, port, var);
145✔
1475

1476
      mir_value_t count = mir_const(mu, t_offset, vlog_size(vlog_type(port)));
145✔
1477

1478
      tree_t map = tree_param(b, i);
145✔
1479
      tree_t value = tree_value(map);
145✔
1480

1481
      mir_value_t in_conv = MIR_NULL_VALUE;
145✔
1482
      if (tree_kind(value) == T_CONV_FUNC) {
145✔
1483
         mir_put_object(mu, map, var);
82✔
1484

1485
         ident_t func = ident_sprintf("%s.%s$verilog_convert_in",
82✔
1486
                                      istr(qual), istr(vlog_ident(port)));
1487
         mir_defer(mc, func, qual, MIR_UNIT_FUNCTION, vlog_lower_convert_in,
82✔
1488
                      tree_to_object(map));
1489

1490
         mir_value_t closure =
82✔
1491
            mir_build_closure(mu, func, self, t_self, t_offset);
82✔
1492
         in_conv = mir_build_port_conversion(mu, closure, closure);
82✔
1493

1494
         value = tree_value(value);
82✔
1495
      }
1496

1497
      assert(tree_kind(value) == T_REF);
145✔
1498

1499
      int nth = mir_find_slot(shape, tree_ident(tree_ref(value)));
145✔
1500
      assert(nth >= 0);
145✔
1501

1502
      mir_value_t upref = mir_build_var_upref(mu, 1, nth);
145✔
1503
      mir_value_t dst_nets = mir_build_load(mu, upref);
145✔
1504

1505
      if (mir_is(mu, dst_nets, MIR_TYPE_UARRAY))
145✔
1506
         dst_nets = mir_build_unwrap(mu, dst_nets);
4✔
1507

1508
      mir_value_t out_conv = MIR_NULL_VALUE;
145✔
1509
      if (tree_subkind(map) == P_NAMED) {
145✔
1510
         tree_t name = tree_name(map);
65✔
1511
         if (tree_kind(name) == T_CONV_FUNC) {
65✔
1512
            mir_put_object(mu, map, var);
37✔
1513

1514
            ident_t func = ident_sprintf("%s.%s$verilog_convert_out",
37✔
1515
                                         istr(qual), istr(vlog_ident(port)));
1516
            mir_defer(mc, func, qual, MIR_UNIT_FUNCTION, vlog_lower_convert_out,
37✔
1517
                      tree_to_object(map));
1518

1519
            mir_value_t closure =
37✔
1520
               mir_build_closure(mu, func, self, t_self, t_offset);
37✔
1521
            out_conv = mir_build_port_conversion(mu, closure, closure);
37✔
1522
         }
1523
      }
1524

1525
      mir_value_t src_nets = mir_build_load(mu, var);
145✔
1526

1527
      if (mir_is(mu, src_nets, MIR_TYPE_UARRAY))
145✔
UNCOV
1528
         src_nets = mir_build_unwrap(mu, src_nets);
×
1529

1530
      switch (vlog_subkind(port)) {
145✔
1531
      case V_PORT_INPUT:
83✔
1532
         if (mir_is_null(in_conv))
83✔
1533
            mir_build_map_signal(mu, dst_nets, src_nets, count);
1✔
1534
         else {
1535
            mir_build_convert_out(mu, in_conv, src_nets, count);
82✔
1536
            mir_build_convert_in(mu, in_conv, dst_nets, count);
82✔
1537
         }
1538
         break;
1539
      case V_PORT_OUTPUT:
62✔
1540
         if (mir_is_null(out_conv))
62✔
1541
            mir_build_map_signal(mu, src_nets, dst_nets, count);
25✔
1542
         else {
1543
            mir_build_convert_out(mu, out_conv, dst_nets, count);
37✔
1544
            mir_build_convert_in(mu, out_conv, src_nets, count);
37✔
1545
         }
1546
         break;
UNCOV
1547
      default:
×
1548
         CANNOT_HANDLE(port);
145✔
1549
      }
1550
   }
1551

1552
   mir_build_return(mu, MIR_NULL_VALUE);
179✔
1553

1554
   hash_free(map);
179✔
1555

1556
   mir_optimise(mu, MIR_PASS_O1);
179✔
1557
   mir_put_unit(mc, mu);
179✔
1558
}
179✔
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