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

nickg / nvc / 18428170938

11 Oct 2025 09:39AM UTC coverage: 92.549% (-0.002%) from 92.551%
18428170938

push

github

nickg
Better handling of System Verilog nulls

40 of 44 new or added lines in 4 files covered. (90.91%)

2 existing lines in 2 files now uncovered.

74468 of 80463 relevant lines covered (92.55%)

446696.77 hits per line

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

94.27
/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
   mir_stamp_t stamp;
40
   unsigned    size;
41
} type_info_t;
42

43
typedef struct {
44
   mir_value_t  nets;
45
   mir_value_t  offset;
46
   mir_value_t  in_range;
47
   unsigned     size;
48
} vlog_lvalue_t;
49

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

52
typedef struct {
53
   mir_unit_t *mu;
54
   ihash_t    *temps;
55
} vlog_gen_t;
56

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

62
static void vlog_lower_stmts(vlog_gen_t *g, vlog_node_t v);
63
static mir_value_t vlog_lower_rvalue(vlog_gen_t *g, vlog_node_t v);
64

65
static const type_info_t *vlog_type_info(vlog_gen_t *g, vlog_node_t v)
5,978✔
66
{
67
   const vlog_kind_t kind = vlog_kind(v);
6,035✔
68
   if (kind == V_TYPE_DECL || kind == V_ENUM_DECL)
6,035✔
69
      return vlog_type_info(g, vlog_type(v));
57✔
70

71
   type_info_t *ti = mir_get_priv(g->mu, v);
5,978✔
72
   if (ti != NULL)
5,978✔
73
      return ti;
74

75
   ti = mir_malloc(g->mu, sizeof(type_info_t));
2,683✔
76
   ti->stamp = MIR_NULL_STAMP;
2,683✔
77
   ti->type  = MIR_NULL_TYPE;
2,683✔
78
   ti->size  = 0;
2,683✔
79

80
   mir_put_priv(g->mu, v, ti);
2,683✔
81

82
   switch (kind) {
2,683✔
83
   case V_DATA_TYPE:
84
      break;
2,677✔
85
   case V_CLASS_DECL:
6✔
86
      {
87
         ident_t name = ident_prefix(vlog_ident2(v), vlog_ident(v), '.');
6✔
88
         ti->type = mir_context_type(g->mu, name);
6✔
89
         return ti;
6✔
90
      }
91
   default:
×
92
      CANNOT_HANDLE(v);
×
93
   }
94

95
   switch (vlog_subkind(v)) {
2,677✔
96
   case DT_LOGIC:
2,548✔
97
   case DT_IMPLICIT:
98
      ti->size = vlog_size(v);
2,548✔
99
      ti->type = mir_vec4_type(g->mu, ti->size, false);
2,548✔
100
      break;
2,548✔
101
   case DT_BIT:
12✔
102
      ti->size = vlog_size(v);
12✔
103
      ti->type = mir_vec2_type(g->mu, ti->size, false);
12✔
104
      break;
12✔
105
   case DT_INTEGER:
78✔
106
      ti->size = 32;
78✔
107
      ti->type = mir_vec4_type(g->mu, ti->size, true);
78✔
108
      break;
78✔
109
   case DT_INT:
27✔
110
      ti->size = 32;
27✔
111
      ti->type = mir_vec2_type(g->mu, ti->size, true);
27✔
112
      break;
27✔
113
   case DT_SHORTINT:
6✔
114
      ti->size = 16;
6✔
115
      ti->type = mir_vec2_type(g->mu, ti->size, true);
6✔
116
      break;
6✔
117
   case DT_LONGINT:
×
118
      ti->size = 64;
×
119
      ti->type = mir_vec2_type(g->mu, ti->size, true);
×
120
      break;
×
121
   case DT_BYTE:
6✔
122
      ti->size = 8;
6✔
123
      ti->type = mir_vec2_type(g->mu, ti->size, true);
6✔
124
      break;
6✔
125
   default:
×
126
      CANNOT_HANDLE(v);
×
127
   }
128

129
   return ti;
130
}
131

132
static mir_value_t vlog_get_temp(vlog_gen_t *g, mir_type_t type)
900✔
133
{
134
   if (g->temps == NULL)
900✔
135
      g->temps = ihash_new(16);
387✔
136
   else {
137
      mir_value_t exist = { .bits = (uintptr_t)ihash_get(g->temps, type.bits) };
513✔
138
      if (!mir_is_null(exist))
513✔
139
         return exist;
465✔
140
   }
141

142
   mir_value_t temp = mir_add_var(g->mu, type, MIR_NULL_STAMP,
435✔
143
                                  ident_uniq("tmp"), MIR_VAR_TEMP);
144

145
   ihash_put(g->temps, type.bits, (void *)(uintptr_t)temp.bits);
435✔
146
   return temp;
435✔
147
}
148

149
static mir_value_t vlog_lower_array_off(vlog_gen_t *g, vlog_node_t r,
486✔
150
                                        vlog_node_t v)
151
{
152
   mir_value_t index = vlog_lower_rvalue(g, v);
486✔
153

154
   mir_type_t index_type = mir_get_type(g->mu, index);
486✔
155
   if (mir_get_class(g->mu, index_type) == MIR_TYPE_VEC4) {
486✔
156
      // TODO: check X/Z handling
157
      const int size = mir_get_size(g->mu, index_type);
486✔
158
      mir_type_t vec2 = mir_vec2_type(g->mu, size, false);
486✔
159
      index = mir_build_cast(g->mu, vec2, index);
486✔
160
   }
161

162
   mir_type_t t_offset = mir_offset_type(g->mu);
486✔
163
   mir_value_t cast = mir_build_cast(g->mu, t_offset, index);
486✔
164

165
   assert(vlog_kind(r) == V_DIMENSION);
486✔
166

167
   int64_t lconst, rconst;
486✔
168
   vlog_bounds(r, &lconst, &rconst);
486✔
169

170
   mir_value_t left = mir_const(g->mu, t_offset, lconst);
486✔
171

172
   if (lconst < rconst)
486✔
173
      return mir_build_sub(g->mu, t_offset, cast, left);
138✔
174
   else
175
      return mir_build_sub(g->mu, t_offset, left, cast);
348✔
176
}
177

178
static mir_value_t vlog_lower_part_select_off(vlog_gen_t *g, vlog_node_t r,
120✔
179
                                              vlog_node_t v)
180
{
181
   mir_value_t base = vlog_lower_array_off(g, r, vlog_left(v));
120✔
182

183
   const vlog_range_kind_t kind = vlog_subkind(v);
120✔
184
   if (kind == V_RANGE_CONST)
120✔
185
      return base;
96✔
186

187
   const bool is_up = vlog_is_up(r);
24✔
188
   if ((kind == V_RANGE_POS && is_up) || (kind == V_RANGE_NEG && !is_up))
24✔
189
      return base;
9✔
190

191
   mir_type_t t_offset = mir_offset_type(g->mu);
15✔
192
   mir_value_t adj = mir_const(g->mu, t_offset, vlog_size(v) - 1);
15✔
193
   return mir_build_sub(g->mu, t_offset, base, adj);
15✔
194
}
195

196
static vlog_lvalue_t vlog_lower_lvalue_ref(vlog_gen_t *g, vlog_node_t v)
2,727✔
197
{
198
   vlog_node_t decl = vlog_ref(v);
2,727✔
199
   if (vlog_kind(decl) == V_PORT_DECL)
2,727✔
200
      decl = vlog_ref(decl);
375✔
201

202
   int hops;
2,727✔
203
   mir_value_t var = mir_search_object(g->mu, decl, &hops);
2,727✔
204
   assert(!mir_is_null(var));
2,727✔
205

206
   mir_value_t ptr = var;
2,727✔
207
   if (hops > 0)
2,727✔
208
      ptr = mir_build_var_upref(g->mu, hops, var.id);
2,694✔
209

210
   mir_value_t nets = ptr;
2,727✔
211
   if (mir_points_to(g->mu, ptr, MIR_TYPE_SIGNAL))
2,727✔
212
      nets = mir_build_load(g->mu, ptr);
2,652✔
213

214
   const type_info_t *ti = vlog_type_info(g, vlog_type(decl));
2,727✔
215

216
   mir_type_t t_bool = mir_bool_type(g->mu);
2,727✔
217
   mir_type_t t_offset = mir_offset_type(g->mu);
2,727✔
218

219
   vlog_lvalue_t result = {
5,454✔
220
      .nets     = nets,
221
      .size     = ti->size,
2,727✔
222
      .offset   = mir_const(g->mu, t_offset, 0),
2,727✔
223
      .in_range = mir_const(g->mu, t_bool, 1),
2,727✔
224
   };
225
   return result;
2,727✔
226
}
227

228
static vlog_lvalue_t vlog_lower_lvalue(vlog_gen_t *g, vlog_node_t v)
3,030✔
229
{
230
   PUSH_DEBUG_INFO(g->mu, v);
6,060✔
231

232
   switch (vlog_kind(v)) {
3,030✔
233
   case V_REF:
2,535✔
234
      return vlog_lower_lvalue_ref(g, v);
2,535✔
235
   case V_HIER_REF:
216✔
236
      {
237
         mir_type_t t_net_value = mir_int_type(g->mu, 0, 255);
216✔
238
         mir_type_t t_net_signal = mir_signal_type(g->mu, t_net_value);
216✔
239

240
         // XXX: reconsider this
241
         ident_t unit_name =
216✔
242
            ident_prefix(mir_get_parent(g->mu), vlog_ident2(v), '.');
216✔
243
         mir_value_t context = mir_build_link_package(g->mu, unit_name);
216✔
244
         mir_value_t ptr = mir_build_link_var(g->mu, context, vlog_ident(v),
216✔
245
                                              t_net_signal);
246

247
         mir_type_t t_bool = mir_bool_type(g->mu);
216✔
248
         mir_type_t t_offset = mir_offset_type(g->mu);
216✔
249

250
         vlog_node_t decl = vlog_ref(v);
216✔
251
         const type_info_t *ti = vlog_type_info(g, vlog_type(decl));
216✔
252

253
         vlog_lvalue_t result = {
432✔
254
            .nets     = mir_build_load(g->mu, ptr),
216✔
255
            .size     = ti->size,
216✔
256
            .offset   = mir_const(g->mu, t_offset, 0),
216✔
257
            .in_range = mir_const(g->mu, t_bool, 1),
216✔
258
         };
259
         return result;
216✔
260
      }
261
   case V_BIT_SELECT:
192✔
262
      {
263
         vlog_node_t prefix = vlog_value(v);
192✔
264
         assert(vlog_kind(prefix) == V_REF);
192✔
265

266
         vlog_lvalue_t ref = vlog_lower_lvalue_ref(g, prefix);
192✔
267

268
         vlog_node_t decl = vlog_ref(prefix), dt = vlog_type(decl);
192✔
269

270
         const int nunpacked = vlog_ranges(decl);
192✔
271
         const int nparams = vlog_params(v);
192✔
272
         assert(nparams <= vlog_ranges(dt) + nunpacked);
192✔
273

274
         unsigned size = vlog_size(decl) * ref.size;
192✔
275

276
         mir_type_t t_offset = mir_offset_type(g->mu);
192✔
277
         mir_value_t zero = mir_const(g->mu, t_offset, 0), off = zero;
192✔
278
         mir_value_t in_range = ref.in_range;
192✔
279

280
         for (int i = 0; i < nparams; i++) {
408✔
281
            vlog_node_t dim;
216✔
282
            if (i < nunpacked)
216✔
283
               dim = vlog_range(decl, i);
84✔
284
            else
285
               dim = vlog_range(dt, i - nunpacked);
132✔
286

287
            const unsigned dim_size = vlog_size(dim);
216✔
288
            assert(size % dim_size == 0);
216✔
289
            size /= dim_size;
216✔
290

291
            mir_value_t this_off =
216✔
292
               vlog_lower_array_off(g, dim, vlog_param(v, i));
216✔
293

294
            mir_value_t count = mir_const(g->mu, t_offset, dim_size);
216✔
295
            mir_value_t cmp_low =
216✔
296
               mir_build_cmp(g->mu, MIR_CMP_GEQ, this_off, zero);
216✔
297
            mir_value_t cmp_high =
216✔
298
               mir_build_cmp(g->mu, MIR_CMP_LT, this_off, count);
216✔
299
            mir_value_t this_in_range = mir_build_and(g->mu, cmp_low, cmp_high);
216✔
300

301
            if (size != 1) {
216✔
302
               mir_value_t scale = mir_const(g->mu, t_offset, size);
84✔
303
               this_off = mir_build_mul(g->mu, t_offset, this_off, scale);
84✔
304
            }
305

306
            in_range = mir_build_and(g->mu, in_range, this_in_range);
216✔
307
            off = mir_build_add(g->mu, t_offset, off, this_off);
216✔
308
         }
309

310
         vlog_lvalue_t lvalue = {
192✔
311
            .nets     = ref.nets,
312
            .offset   = off,
313
            .size     = size,
314
            .in_range = in_range,
315
         };
316
         return lvalue;
192✔
317
      }
318
   case V_PART_SELECT:
75✔
319
      {
320
         vlog_lvalue_t prefix = vlog_lower_lvalue(g, vlog_value(v));
75✔
321

322
         vlog_node_t dt = vlog_type(vlog_ref(vlog_value(v)));
75✔
323
         vlog_node_t dim = vlog_range(dt, 0);
75✔
324

325
         mir_value_t off = vlog_lower_part_select_off(g, dim, v);
75✔
326

327
         mir_type_t t_offset = mir_offset_type(g->mu);
75✔
328

329
         vlog_lvalue_t lvalue = {
225✔
330
            .nets     = prefix.nets,
331
            .offset   = mir_build_add(g->mu, t_offset, off, prefix.offset),
75✔
332
            .size     = vlog_size(v),
75✔
333
            .in_range = prefix.in_range,   // XXX
334
         };
335
         return lvalue;
75✔
336
      }
337
   case V_MEMBER_REF:
12✔
338
      {
339
         vlog_lvalue_t prefix = vlog_lower_lvalue(g, vlog_value(v));
12✔
340
         assert(mir_points_to(g->mu, prefix.nets, MIR_TYPE_CONTEXT));
12✔
341

342
         const type_info_t *ti = vlog_type_info(g, vlog_type(vlog_ref(v)));
12✔
343

344
         mir_value_t context = mir_build_load(g->mu, prefix.nets);
12✔
345
         mir_value_t link = mir_build_link_var(g->mu, context,
12✔
346
                                               vlog_ident(v), ti->type);
347

348
         vlog_lvalue_t lvalue = {
12✔
349
            .nets     = link,
350
            .offset   = MIR_NULL_VALUE,
351
            .size     = 1,
352
            .in_range = prefix.in_range,
353
         };
354
         return lvalue;
12✔
355
      }
356
   default:
×
357
      CANNOT_HANDLE(v);
3,030✔
358
   }
359
}
360

361
static void vlog_assign_variable(vlog_gen_t *g, vlog_node_t target,
1,227✔
362
                                 mir_value_t value)
363
{
364
   unsigned nlvalues = 1, targetsz = 0;
1,227✔
365
   vlog_lvalue_t lvalue1, *lvalues = &lvalue1;
1,227✔
366
   if (vlog_kind(target) == V_CONCAT) {
1,227✔
367
      const int nparams = nlvalues = vlog_params(target);
3✔
368
      lvalues = xmalloc_array(nparams, sizeof(vlog_lvalue_t));
3✔
369
      for (int i = 0; i < nparams; i++) {
12✔
370
         lvalues[i] = vlog_lower_lvalue(g, vlog_param(target, i));
9✔
371
         targetsz += lvalues[i].size;
9✔
372
      }
373
   }
374
   else {
375
      lvalue1 = vlog_lower_lvalue(g, target);
1,224✔
376
      targetsz = lvalue1.size;
1,224✔
377
   }
378

379
   mir_block_t merge_bb = MIR_NULL_BLOCK;
1,227✔
380

381
   int64_t in_range_const;
1,227✔
382
   if (mir_get_const(g->mu, lvalues[0].in_range, &in_range_const)) {
1,227✔
383
      if (!in_range_const) {
1,224✔
384
         mir_comment(g->mu, "Out-of-range assignment");
9✔
385
         return;
9✔
386
      }
387
   }
388
   else {
389
      mir_block_t guarded_bb = mir_add_block(g->mu);
3✔
390
      merge_bb = mir_add_block(g->mu);
3✔
391

392
      mir_build_cond(g->mu, lvalues[0].in_range, guarded_bb, merge_bb);
3✔
393

394
      mir_set_cursor(g->mu, guarded_bb, MIR_APPEND);
3✔
395
   }
396

397
   if (mir_is_signal(g->mu, lvalues[0].nets)) {
1,218✔
398
      mir_value_t tmp = MIR_NULL_VALUE;
1,143✔
399
      if (targetsz > 1) {
1,143✔
400
         mir_type_t t_elem = mir_logic_type(g->mu);
657✔
401
         mir_type_t t_array = mir_carray_type(g->mu, targetsz, t_elem);
657✔
402
         tmp = vlog_get_temp(g, t_array);
657✔
403
      }
404

405
      mir_type_t t_vec = mir_vec4_type(g->mu, targetsz, false);
1,143✔
406
      mir_type_t t_offset = mir_offset_type(g->mu);
1,143✔
407

408
      mir_value_t resize = mir_build_cast(g->mu, t_vec, value);
1,143✔
409
      mir_value_t unpacked = mir_build_unpack(g->mu, resize, 0, tmp);
1,143✔
410

411
      for (int i = 0, offset = 0; i < nlvalues;
2,292✔
412
           offset += lvalues[i].size, i++) {
1,149✔
413
         mir_value_t nets = mir_build_array_ref(g->mu, lvalues[i].nets,
1,149✔
414
                                                lvalues[i].offset);
1,149✔
415

416
         mir_value_t count = mir_const(g->mu, t_offset, lvalues[i].size);
1,149✔
417

418
         mir_value_t src = unpacked;
1,149✔
419
         if (offset > 0) {
1,149✔
420
            mir_value_t pos = mir_const(g->mu, t_offset, offset);
6✔
421
            src = mir_build_array_ref(g->mu, unpacked, pos);
6✔
422
         }
423

424
         mir_build_deposit_signal(g->mu, nets, count, src);
1,149✔
425
      }
426
   }
427
   else {
428
      assert(nlvalues == 1);  // TODO
75✔
429

430
      mir_type_t t_pointer = mir_get_type(g->mu, lvalues[0].nets);
75✔
431
      mir_type_t t_vec = mir_get_pointer(g->mu, t_pointer);
75✔
432

433
      switch (vlog_kind(target)) {
75✔
434
      case V_REF:
72✔
435
      case V_MEMBER_REF:
436
         {
437
            mir_value_t resize = mir_build_cast(g->mu, t_vec, value);
72✔
438
            mir_build_store(g->mu, lvalues[0].nets, resize);
72✔
439
         }
440
         break;
72✔
441
      default:
3✔
442
         {
443
            const bool issigned = mir_get_signed(g->mu, t_vec);
3✔
444
            mir_type_t t_part = mir_vec4_type(g->mu, lvalues[0].size, issigned);
3✔
445
            mir_value_t resize = mir_build_cast(g->mu, t_part, value);
3✔
446
            mir_value_t cur = mir_build_load(g->mu, lvalues[0].nets);
3✔
447
            mir_value_t ins =
3✔
448
               mir_build_insert(g->mu, resize, cur, lvalues[0].offset);
3✔
449
            mir_build_store(g->mu, lvalues[0].nets, ins);
3✔
450
         }
451
         break;
3✔
452
      }
453
   }
454

455
   if (!mir_is_null(merge_bb)) {
1,218✔
456
      mir_build_jump(g->mu, merge_bb);
3✔
457

458
      mir_set_cursor(g->mu, merge_bb, MIR_APPEND);
3✔
459
   }
460
}
461

462
static mir_value_t vlog_lower_unary(vlog_gen_t *g, vlog_node_t v)
105✔
463
{
464
   mir_value_t input = vlog_lower_rvalue(g, vlog_value(v));
105✔
465
   mir_type_t type = mir_get_type(g->mu, input);
105✔
466

467
   bool negate = false;
105✔
468
   mir_vec_op_t mop;
105✔
469
   switch (vlog_subkind(v)) {
105✔
470
   case V_UNARY_BITNEG: mop = MIR_VEC_BIT_NOT; break;
471
   case V_UNARY_NOT:    mop = MIR_VEC_LOG_NOT; break;
39✔
472
   case V_UNARY_NEG:    mop = MIR_VEC_SUB; break;
×
473
   case V_UNARY_OR:     mop = MIR_VEC_BIT_OR; break;
6✔
474
   case V_UNARY_XOR:    mop = MIR_VEC_BIT_XOR; break;
6✔
475
   case V_UNARY_AND:    mop = MIR_VEC_BIT_AND; break;
9✔
476
   case V_UNARY_NAND:   mop = MIR_VEC_BIT_AND; negate = true; break;
3✔
477
   case V_UNARY_NOR:    mop = MIR_VEC_BIT_OR; negate = true; break;
3✔
478
   case V_UNARY_XNOR:   mop = MIR_VEC_BIT_XOR; negate = true; break;
×
479
   default:
×
480
      CANNOT_HANDLE(v);
×
481
   }
482

483
   mir_value_t result = mir_build_unary(g->mu, mop, type, input);
105✔
484
   if (!negate)
105✔
485
      return result;
99✔
486

487
   mir_type_t otype = mir_get_type(g->mu, result);
6✔
488
   assert(mir_get_size(g->mu, otype) == 1);
6✔
489

490
   return mir_build_unary(g->mu, MIR_VEC_BIT_NOT, otype, result);
6✔
491
}
492

493
static bool vlog_has_side_effects(vlog_node_t v)
396✔
494
{
495
   switch (vlog_kind(v)) {
396✔
496
   case V_REF:
497
   case V_BIT_SELECT:
498
   case V_PART_SELECT:
499
   case V_NUMBER:
500
      return false;
501
   case V_UNARY:
×
502
      return vlog_has_side_effects(vlog_value(v));
×
503
   case V_BINARY:
135✔
504
      return vlog_has_side_effects(vlog_left(v))
135✔
505
         || vlog_has_side_effects(vlog_right(v));
138✔
506
   default:
18✔
507
      return true;
18✔
508
   }
509
}
510

511
static mir_value_t vlog_lower_vector_binary(vlog_gen_t *g, vlog_binary_t binop,
1,089✔
512
                                            mir_value_t left, mir_value_t right)
513
{
514
   mir_type_t ltype = mir_get_type(g->mu, left);
1,089✔
515
   mir_type_t rtype = mir_get_type(g->mu, right);
1,089✔
516

517
   const mir_class_t lclass = mir_get_class(g->mu, ltype);
1,089✔
518
   const mir_class_t rclass = mir_get_class(g->mu, rtype);
1,089✔
519

520
   const int lsize = mir_get_size(g->mu, ltype);
1,089✔
521
   const int rsize = mir_get_size(g->mu, rtype);
1,089✔
522

523
   const bool is_signed =
2,178✔
524
      mir_get_signed(g->mu, ltype) || mir_get_signed(g->mu, rtype);
1,089✔
525

526
   mir_type_t type;
1,089✔
527
   if (lclass == MIR_TYPE_VEC4 || rclass == MIR_TYPE_VEC4)
1,089✔
528
      type = mir_vec4_type(g->mu, MAX(lsize, rsize), is_signed);
1,089✔
529
   else
530
      type = mir_vec2_type(g->mu, MAX(lsize, rsize), is_signed);
×
531

532
   mir_value_t lcast = mir_build_cast(g->mu, type, left);
1,089✔
533
   mir_value_t rcast = mir_build_cast(g->mu, type, right);
1,089✔
534

535
   bool negate = false;
1,089✔
536
   mir_vec_op_t mop;
1,089✔
537
   switch (binop) {
1,089✔
538
   case V_BINARY_AND:      mop = MIR_VEC_BIT_AND; break;
539
   case V_BINARY_OR:       mop = MIR_VEC_BIT_OR; break;
21✔
540
   case V_BINARY_XOR:      mop = MIR_VEC_BIT_XOR; break;
6✔
541
   case V_BINARY_XNOR:     mop = MIR_VEC_BIT_XOR; negate = true; break;
3✔
542
   case V_BINARY_LOG_AND:  mop = MIR_VEC_LOG_AND; break;
36✔
543
   case V_BINARY_LOG_OR:   mop = MIR_VEC_LOG_OR; break;
102✔
544
   case V_BINARY_LT:       mop = MIR_VEC_LT; break;
45✔
545
   case V_BINARY_LEQ:      mop = MIR_VEC_LEQ; break;
12✔
546
   case V_BINARY_GT:       mop = MIR_VEC_GT; break;
9✔
547
   case V_BINARY_GEQ:      mop = MIR_VEC_GEQ; break;
15✔
548
   case V_BINARY_LOG_EQ:   mop = MIR_VEC_LOG_EQ; break;
60✔
549
   case V_BINARY_LOG_NEQ:  mop = MIR_VEC_LOG_NEQ; break;
39✔
550
   case V_BINARY_CASE_EQ:  mop = MIR_VEC_CASE_EQ; break;
72✔
551
   case V_BINARY_CASE_NEQ: mop = MIR_VEC_CASE_NEQ; break;
444✔
552
   case V_BINARY_PLUS:     mop = MIR_VEC_ADD; break;
87✔
553
   case V_BINARY_MINUS:    mop = MIR_VEC_SUB; break;
18✔
554
   case V_BINARY_TIMES:    mop = MIR_VEC_MUL; break;
24✔
555
   case V_BINARY_DIVIDE:   mop = MIR_VEC_DIV; break;
9✔
556
   case V_BINARY_MOD:      mop = MIR_VEC_MOD; break;
6✔
557
   case V_BINARY_SHIFT_LL: mop = MIR_VEC_SLL; break;
15✔
558
   case V_BINARY_SHIFT_RL: mop = MIR_VEC_SRL; break;
12✔
559
   case V_BINARY_SHIFT_RA: mop = MIR_VEC_SRA; break;
3✔
560
   case V_BINARY_SHIFT_LA: mop = MIR_VEC_SLA; break;
3✔
561
   default: should_not_reach_here();
562
   }
563

564
   mir_value_t result = mir_build_binary(g->mu, mop, type, lcast, rcast);
1,089✔
565
   if (negate) {
1,089✔
566
      mir_type_t otype = mir_get_type(g->mu, result);
3✔
567
      return mir_build_unary(g->mu, MIR_VEC_BIT_NOT, otype, result);
3✔
568
   }
569

570
   return result;
1,086✔
571
}
572

573
static mir_value_t vlog_lower_binary(vlog_gen_t *g, vlog_node_t v)
1,095✔
574
{
575
   mir_value_t left = vlog_lower_rvalue(g, vlog_left(v));
1,095✔
576

577
   // For short-circuiting operators check if the RHS can have side effects
578
   vlog_node_t rhs_expr = vlog_right(v);
1,095✔
579
   mir_block_t guard_bb = MIR_NULL_BLOCK, skip_bb = MIR_NULL_BLOCK;
1,095✔
580
   mir_value_t var = MIR_NULL_VALUE;
1,095✔
581
   const vlog_binary_t binop = vlog_subkind(v);
1,095✔
582
   const bool is_short_circuit =
1,095✔
583
      binop == V_BINARY_LOG_AND || binop == V_BINARY_LOG_OR;
1,095✔
584

585
   if (is_short_circuit && vlog_has_side_effects(rhs_expr)) {
1,095✔
586
      guard_bb = mir_add_block(g->mu);
18✔
587
      skip_bb = mir_add_block(g->mu);
18✔
588

589
      // TODO: use a phi
590
      mir_type_t t_logic = mir_vec4_type(g->mu, 1, false);
18✔
591
      var = mir_add_var(g->mu, t_logic, MIR_NULL_STAMP,
18✔
592
                        ident_uniq("shortcircuit"), MIR_VAR_TEMP);
593

594
      mir_value_t def = mir_const_vec(g->mu, t_logic,
18✔
595
                                      binop == V_BINARY_LOG_OR, 0);
596
      mir_build_store(g->mu, var, def);
18✔
597

598
      mir_value_t test = mir_build_test(g->mu, left);
18✔
599
      if (binop == V_BINARY_LOG_OR)
18✔
600
         mir_build_cond(g->mu, test, skip_bb, guard_bb);
15✔
601
      else
602
         mir_build_cond(g->mu, test, guard_bb, skip_bb);
3✔
603

604
      mir_set_cursor(g->mu, guard_bb, MIR_APPEND);
18✔
605
   }
606

607
   mir_value_t right = vlog_lower_rvalue(g, rhs_expr), result;
1,095✔
608

609
   if (mir_is_vector(g->mu, left))
1,095✔
610
      result = vlog_lower_vector_binary(g, binop, left, right);
1,089✔
611
   else {
612
      switch (binop) {
6✔
613
      case V_BINARY_LOG_EQ:
3✔
614
      case V_BINARY_CASE_EQ:
615
         result = mir_build_cmp(g->mu, MIR_CMP_EQ, left, right);
3✔
616
         break;
3✔
617
      case V_BINARY_LOG_NEQ:
3✔
618
      case V_BINARY_CASE_NEQ:
619
         result = mir_build_cmp(g->mu, MIR_CMP_NEQ, left, right);
3✔
620
         break;
3✔
621
      default:
×
622
         CANNOT_HANDLE(v);
×
623
      }
624
   }
625

626
   if (mir_is_null(var))
1,095✔
627
      return result;
1,077✔
628

629
   mir_build_store(g->mu, var, result);
18✔
630

631
   mir_set_cursor(g->mu, skip_bb, MIR_APPEND);
18✔
632

633
   return mir_build_load(g->mu, var);
18✔
634
}
635

636
static mir_value_t vlog_lower_operator_assignment(vlog_gen_t *g, vlog_node_t v)
75✔
637
{
638
   vlog_node_t target = vlog_target(v);
75✔
639

640
   mir_value_t value = vlog_lower_rvalue(g, vlog_value(v));
75✔
641
   mir_value_t cur = vlog_lower_rvalue(g, target);
75✔
642

643
   const vlog_assign_t kind = vlog_subkind(v);
75✔
644
   if (kind != V_ASSIGN_EQUALS) {
75✔
645
      mir_type_t type = mir_get_type(g->mu, cur);
45✔
646
      mir_value_t cast = mir_build_cast(g->mu, type, value);
45✔
647

648
      mir_vec_op_t op;
45✔
649
      switch (kind) {
45✔
650
      case V_ASSIGN_PLUS:     op = MIR_VEC_ADD; break;
651
      case V_ASSIGN_MINUS:    op = MIR_VEC_SUB; break;
652
      case V_ASSIGN_TIMES:    op = MIR_VEC_MUL; break;
653
      case V_ASSIGN_DIVIDE:   op = MIR_VEC_DIV; break;
654
      case V_ASSIGN_MOD:      op = MIR_VEC_MOD; break;
655
      case V_ASSIGN_AND:      op = MIR_VEC_BIT_AND; break;
656
      case V_ASSIGN_OR:       op = MIR_VEC_BIT_OR; break;
657
      case V_ASSIGN_XOR:      op = MIR_VEC_BIT_XOR; break;
658
      case V_ASSIGN_SHIFT_LL: op = MIR_VEC_SLL; break;
659
      case V_ASSIGN_SHIFT_RL: op = MIR_VEC_SRL; break;
660
      case V_ASSIGN_SHIFT_LA: op = MIR_VEC_SLA; break;
661
      case V_ASSIGN_SHIFT_RA: op = MIR_VEC_SRA; break;
662
      default:
×
663
         CANNOT_HANDLE(v);
×
664
      }
665

666
      value = mir_build_binary(g->mu, op, type, cur, cast);
45✔
667
   }
668

669
   vlog_assign_variable(g, target, value);
75✔
670
   return value;
75✔
671
}
672

673
static mir_value_t vlog_lower_systf_param(vlog_gen_t *g, vlog_node_t v)
1,647✔
674
{
675
   switch (vlog_kind(v)) {
1,647✔
676
   case V_REF:
588✔
677
      switch (vlog_kind(vlog_ref(v))) {
588✔
678
      case V_TF_PORT_DECL:
9✔
679
      case V_FUNC_DECL:
680
         return vlog_lower_rvalue(g, v);
9✔
681
      default:
579✔
682
         return MIR_NULL_VALUE;
579✔
683
      }
684
   case V_STRING:
888✔
685
   case V_NUMBER:
686
   case V_EMPTY:
687
      return MIR_NULL_VALUE;
888✔
688
   case V_UNARY:
171✔
689
   case V_BINARY:
690
   case V_SYS_FCALL:
691
   case V_PREFIX:
692
   case V_POSTFIX:
693
   case V_BIT_SELECT:
694
   case V_PART_SELECT:
695
   case V_COND_EXPR:
696
   case V_MEMBER_REF:
697
      // TODO: these should not be evaluated until vpi_get_value is called
698
      return vlog_lower_rvalue(g, v);
171✔
699
   default:
×
700
      CANNOT_HANDLE(v);
×
701
   }
702
}
703

704
static mir_value_t vlog_lower_sys_tfcall(vlog_gen_t *g, vlog_node_t v)
1,203✔
705
{
706
   const int nparams = vlog_params(v);
1,203✔
707
   mir_value_t *args LOCAL =
2,406✔
708
      xmalloc_array((nparams * 2) + 1, sizeof(mir_value_t));
1,203✔
709
   int actual = 0;
1,203✔
710
   mir_type_t t_offset = mir_offset_type(g->mu);
1,203✔
711
   for (int i = 0; i < nparams; i++) {
2,850✔
712
      mir_value_t arg = vlog_lower_systf_param(g, vlog_param(v, i));
1,647✔
713
      if (mir_is_null(arg))
1,647✔
714
         continue;
1,467✔
715

716
      mir_type_t type = mir_get_type(g->mu, arg);
180✔
717
      switch (mir_get_class(g->mu, type)) {
180✔
718
      case MIR_TYPE_VEC4:
75✔
719
         args[actual++] = mir_const(g->mu, t_offset, mir_get_size(g->mu, type));
75✔
720
         args[actual++] = arg;
75✔
721
         break;
75✔
722
      case MIR_TYPE_VEC2:
105✔
723
         {
724
            // TODO: remove the cast
725
            const int size = mir_get_size(g->mu, type);
105✔
726
            mir_type_t t_vec4 = mir_vec4_type(g->mu, size, false);
105✔
727
            args[actual++] = mir_const(g->mu, t_offset, size);
105✔
728
            args[actual++] = mir_build_cast(g->mu, t_vec4, arg);
105✔
729
         }
730
         break;
105✔
731
      default:
×
732
         should_not_reach_here();
733
      }
734
   }
735

736
   mir_value_t locus = mir_build_locus(g->mu, vlog_to_object(v));
1,203✔
737

738
   mir_type_t type = MIR_NULL_TYPE;
1,203✔
739
   if (vlog_kind(v) == V_SYS_FCALL)
1,203✔
740
      type = mir_vec2_type(g->mu, 64, false);  // XXX: hack for $time
78✔
741

742
   return mir_build_syscall(g->mu, vlog_ident(v), type, MIR_NULL_STAMP,
1,203✔
743
                            locus, args, actual);
744
}
745

746
static mir_value_t vlog_lower_resolved(vlog_gen_t *g, vlog_node_t v)
1,839✔
747
{
748
   switch (vlog_kind(v)) {
2,199✔
749
   case V_PORT_DECL:
360✔
750
   case V_REF:
751
      return vlog_lower_resolved(g, vlog_ref(v));
360✔
752
   case V_VAR_DECL:
1,773✔
753
   case V_NET_DECL:
754
   case V_FUNC_DECL:
755
   case V_GENVAR_DECL:
756
      {
757
         int hops;
1,773✔
758
         mir_value_t var = mir_search_object(g->mu, v, &hops), val;
1,773✔
759
         assert(!mir_is_null(var));
1,773✔
760

761
         if (hops == 0)
1,773✔
762
            val = mir_build_load(g->mu, var);
24✔
763
         else {
764
            mir_value_t upref = mir_build_var_upref(g->mu, hops, var.id);
1,749✔
765
            val = mir_build_load(g->mu, upref);
1,749✔
766
         }
767

768
         if (mir_is_signal(g->mu, val))
1,773✔
769
            return mir_build_resolved(g->mu, val);
1,674✔
770
         else
771
            return val;
99✔
772
      }
773
   case V_TF_PORT_DECL:
48✔
774
      {
775
         int hops;
48✔
776
         mir_value_t param = mir_search_object(g->mu, v, &hops);
48✔
777
         assert(!mir_is_null(param));
48✔
778
         assert(param.tag == MIR_TAG_PARAM);
48✔
779
         assert(hops == 0);
48✔
780
         return param;
48✔
781
      }
782
   case V_ENUM_NAME:
18✔
783
      return vlog_lower_rvalue(g, vlog_value(v));
18✔
784
   default:
×
785
      CANNOT_HANDLE(v);
×
786
   }
787
}
788

789
static mir_value_t vlog_lower_bit_select(vlog_gen_t *g, vlog_node_t v)
129✔
790
{
791
   vlog_node_t value = vlog_value(v);
129✔
792
   assert(vlog_kind(value) == V_REF);
129✔
793

794
   mir_value_t data = vlog_lower_resolved(g, value);
129✔
795

796
   vlog_node_t decl = vlog_ref(value), dt = vlog_type(decl);
129✔
797

798
   const int nunpacked = vlog_ranges(decl);
129✔
799
   const int nparams = vlog_params(v);
129✔
800
   assert(nparams <= vlog_ranges(dt) + nunpacked);
129✔
801

802
   unsigned size = vlog_size(decl) * vlog_size(dt);
129✔
803

804
   mir_type_t t_offset = mir_offset_type(g->mu);
129✔
805
   mir_value_t zero = mir_const(g->mu, t_offset, 0), off = zero;
129✔
806
   mir_value_t in_range = mir_const(g->mu, mir_bool_type(g->mu), 1);
129✔
807

808
   for (int i = 0; i < nparams; i++) {
279✔
809
      vlog_node_t dim;
150✔
810
      if (i < nunpacked)
150✔
811
         dim = vlog_range(decl, i);
81✔
812
      else
813
         dim = vlog_range(dt, i - nunpacked);
69✔
814

815
      const unsigned dim_size = vlog_size(dim);
150✔
816
      assert(size % dim_size == 0);
150✔
817
      size /= dim_size;
150✔
818

819
      mir_value_t this_off = vlog_lower_array_off(g, dim, vlog_param(v, i));
150✔
820

821
      mir_value_t count = mir_const(g->mu, t_offset, dim_size);
150✔
822

823
      mir_value_t cmp_low = mir_build_cmp(g->mu, MIR_CMP_GEQ, this_off, zero);
150✔
824
      mir_value_t cmp_high = mir_build_cmp(g->mu, MIR_CMP_LT, this_off, count);
150✔
825
      mir_value_t this_in_range = mir_build_and(g->mu, cmp_low, cmp_high);
150✔
826

827
      if (size != 1) {
150✔
828
         mir_value_t scale = mir_const(g->mu, t_offset, size);
81✔
829
         this_off = mir_build_mul(g->mu, t_offset, this_off, scale);
81✔
830
      }
831

832
      in_range = mir_build_and(g->mu, in_range, this_in_range);
150✔
833
      off = mir_build_add(g->mu, t_offset, off, this_off);
150✔
834
   }
835

836
   mir_type_t type = mir_vec4_type(g->mu, size, false);
129✔
837

838
   mir_block_t merge_bb = MIR_NULL_BLOCK;
129✔
839
   mir_value_t tmp;
129✔
840
   int64_t in_range_const;
129✔
841
   if (mir_get_const(g->mu, in_range, &in_range_const)) {
129✔
842
      if (!in_range_const)
102✔
843
         return mir_const_vec(g->mu, type, 1, 1);
6✔
844
   }
845
   else {
846
      // TODO: use a phi node here
847
      tmp = mir_add_var(g->mu, type, MIR_NULL_STAMP,
27✔
848
                        ident_uniq("tmp"), MIR_VAR_TEMP);
849
      mir_build_store(g->mu, tmp, mir_const_vec(g->mu, type, 1, 1));
27✔
850

851
      mir_block_t guarded_bb = mir_add_block(g->mu);
27✔
852
      merge_bb = mir_add_block(g->mu);
27✔
853

854
      mir_build_cond(g->mu, in_range, guarded_bb, merge_bb);
27✔
855

856
      mir_set_cursor(g->mu, guarded_bb, MIR_APPEND);
27✔
857
   }
858

859
   mir_value_t packed;
123✔
860
   if (mir_is_vector(g->mu, data))
123✔
861
      packed = mir_build_extract(g->mu, type, data, off);
3✔
862
   else {
863
      mir_value_t ptr = mir_build_array_ref(g->mu, data, off);
120✔
864
      if (size == 1) {
120✔
865
         mir_value_t bit = mir_build_load(g->mu, ptr);
60✔
866
         packed = mir_build_pack(g->mu, type, bit);
60✔
867
      }
868
      else
869
         packed = mir_build_pack(g->mu, type, ptr);
60✔
870
   }
871

872
   if (mir_is_null(merge_bb))
123✔
873
      return packed;
96✔
874
   else {
875
      mir_build_store(g->mu, tmp, packed);
27✔
876
      mir_build_jump(g->mu, merge_bb);
27✔
877

878
      mir_set_cursor(g->mu, merge_bb, MIR_APPEND);
27✔
879

880
      return mir_build_load(g->mu, tmp);
27✔
881
   }
882
}
883

884
static mir_value_t vlog_lower_sys_fcall(vlog_gen_t *g, vlog_node_t v)
90✔
885
{
886
   switch (is_well_known(vlog_ident(v))) {
90✔
887
   case W_DLR_SIGNED:
12✔
888
      {
889
         mir_value_t arg = vlog_lower_rvalue(g, vlog_param(v, 0));
12✔
890
         mir_type_t arg_type = mir_get_type(g->mu, arg), type;
12✔
891
         switch (mir_get_class(g->mu, arg_type)) {
12✔
892
         case MIR_TYPE_VEC2:
×
893
            type = mir_vec2_type(g->mu, mir_get_size(g->mu, arg_type), true);
×
894
            break;
×
895
         case MIR_TYPE_VEC4:
12✔
896
            type = mir_vec4_type(g->mu, mir_get_size(g->mu, arg_type), true);
12✔
897
            break;
12✔
898
         default:
×
899
            type = arg_type;
×
900
            break;
×
901
         }
902

903
         return mir_build_cast(g->mu, type, arg);
12✔
904
      }
905
   default:
78✔
906
      return vlog_lower_sys_tfcall(g, v);
78✔
907
   }
908
}
909

910
static mir_value_t vlog_lower_rvalue(vlog_gen_t *g, vlog_node_t v)
6,441✔
911
{
912
   PUSH_DEBUG_INFO(g->mu, v);
12,882✔
913

914
   switch (vlog_kind(v)) {
6,441✔
915
   case V_REF:
1,665✔
916
      {
917
         vlog_node_t decl = vlog_ref(v);
1,665✔
918
         if (vlog_kind(decl) == V_LOCALPARAM)
1,665✔
919
            return vlog_lower_rvalue(g, vlog_value(decl));
×
920

921
         mir_value_t data = vlog_lower_resolved(g, decl);
1,665✔
922
         if (mir_is_vector(g->mu, data))
1,665✔
923
            return data;
93✔
924

925
         const type_info_t *ti = vlog_type_info(g, vlog_type(decl));
1,572✔
926

927
         switch (mir_get_class(g->mu, ti->type)) {
1,572✔
928
         case MIR_TYPE_VEC2:
1,515✔
929
         case MIR_TYPE_VEC4:
930
            if (ti->size == 1)
1,515✔
931
               data = mir_build_load(g->mu, data);
552✔
932
            return mir_build_pack(g->mu, ti->type, data);
1,515✔
933
         case MIR_TYPE_CONTEXT:
57✔
934
            return data;
57✔
935
         default:
×
936
            CANNOT_HANDLE(v);
×
937
         }
938
      }
939
   case V_HIER_REF:
60✔
940
      {
941
         mir_type_t t_net_value = mir_int_type(g->mu, 0, 255);
60✔
942
         mir_type_t t_net_signal = mir_signal_type(g->mu, t_net_value);
60✔
943

944
         // XXX: reconsider this
945
         ident_t unit_name =
60✔
946
            ident_prefix(mir_get_parent(g->mu), vlog_ident2(v), '.');
60✔
947
         mir_value_t context = mir_build_link_package(g->mu, unit_name);
60✔
948
         mir_value_t ptr = mir_build_link_var(g->mu, context, vlog_ident(v),
60✔
949
                                              t_net_signal);
950
         mir_value_t nets = mir_build_load(g->mu, ptr);
60✔
951

952
         vlog_node_t decl = vlog_ref(v);
60✔
953
         const type_info_t *ti = vlog_type_info(g, vlog_type(decl));
60✔
954

955
         mir_value_t data = mir_build_resolved(g->mu, nets);
60✔
956

957
         if (ti->size == 1)
60✔
958
            data = mir_build_load(g->mu, data);
42✔
959

960
         return mir_build_pack(g->mu, ti->type, data);
60✔
961
      }
962
   case V_NUMBER:
3,018✔
963
   case V_STRING:
964
      {
965
         number_t num = vlog_number(v);
3,018✔
966
         const int width = number_width(num);
3,018✔
967

968
         const uint64_t *abits, *bbits;
3,018✔
969
         number_get(num, &abits, &bbits);
3,018✔
970

971
         mir_type_t t_low = mir_vec4_type(g->mu, MIN(width, 64), false);
3,018✔
972
         mir_value_t low = mir_const_vec(g->mu, t_low, abits[0], bbits[0]);
3,018✔
973

974
         if (width <= 64)
3,018✔
975
            return low;
3,003✔
976

977
         mir_type_t t_full = mir_vec4_type(g->mu, width, false);
15✔
978
         mir_value_t full = mir_build_cast(g->mu, t_full, low);
15✔
979

980
         mir_type_t t_offset = mir_offset_type(g->mu);
15✔
981

982
         for (int i = 64; i < width; i += 64) {
54✔
983
            const uint64_t aword = abits[i / 64];
39✔
984
            const uint64_t bword = bbits[i / 64];
39✔
985
            if (aword == 0 && bword == 0)
39✔
986
               continue;
24✔
987

988
            const int part_size = MIN(width - i, 64);
15✔
989

990
            mir_type_t t_part = mir_vec4_type(g->mu, part_size, false);
15✔
991
            mir_value_t part = mir_const_vec(g->mu, t_part, aword, bword);
15✔
992

993
            mir_value_t pos = mir_const(g->mu, t_offset, width - i - part_size);
15✔
994
            full = mir_build_insert(g->mu, part, full, pos);
15✔
995
         }
996

997
         return full;
15✔
998
      }
999
   case V_BINARY:
1,095✔
1000
      return vlog_lower_binary(g, v);
1,095✔
1001
   case V_UNARY:
105✔
1002
      return vlog_lower_unary(g, v);
105✔
1003
   case V_SYS_FCALL:
90✔
1004
      return vlog_lower_sys_fcall(g, v);
90✔
1005
   case V_BIT_SELECT:
129✔
1006
      return vlog_lower_bit_select(g, v);
129✔
1007
   case V_PART_SELECT:
45✔
1008
      {
1009
         mir_value_t base = vlog_lower_resolved(g, vlog_value(v));
45✔
1010

1011
         vlog_node_t dt = vlog_type(vlog_ref(vlog_value(v)));
45✔
1012
         vlog_node_t dim = vlog_range(dt, 0);
45✔
1013

1014
         mir_value_t off = vlog_lower_part_select_off(g, dim, v);
45✔
1015

1016
         mir_type_t t_vec = mir_vec4_type(g->mu, vlog_size(v), false);
45✔
1017

1018
         if (mir_is_vector(g->mu, base))
45✔
1019
            return mir_build_extract(g->mu, t_vec, base, off);
12✔
1020
         else {
1021
            mir_value_t ptr = mir_build_array_ref(g->mu, base, off);
33✔
1022
            return mir_build_pack(g->mu, t_vec, ptr);
33✔
1023
         }
1024
      }
1025
   case V_CONCAT:
39✔
1026
      {
1027
         int size = 0, repeat = 1;
39✔
1028
         const int nparams = vlog_params(v);
39✔
1029
         mir_value_t *inputs LOCAL =
39✔
1030
            xmalloc_array(nparams, sizeof(mir_value_t));
39✔
1031

1032
         for (int i = 0; i < nparams; i++) {
99✔
1033
            inputs[i] = vlog_lower_rvalue(g, vlog_param(v, i));
60✔
1034
            assert(mir_is_vector(g->mu, inputs[i]));
60✔
1035

1036
            mir_type_t part_type = mir_get_type(g->mu, inputs[i]);
60✔
1037
            int part_size = mir_get_size(g->mu, part_type);
60✔
1038

1039
            if (mir_get_class(g->mu, part_type) != MIR_TYPE_VEC4) {
60✔
1040
               mir_type_t t_vec4 = mir_vec4_type(g->mu, part_size, false);
×
1041
               inputs[i] = mir_build_cast(g->mu, t_vec4, inputs[i]);
×
1042
            }
1043

1044
            size += part_size;
60✔
1045
         }
1046

1047
         if (vlog_has_value(v)) {
39✔
1048
            int64_t cval;
21✔
1049
            vlog_get_const(vlog_value(v), &cval);
21✔
1050
            size *= (repeat = MAX(0, cval));
21✔
1051
         }
1052

1053
         mir_type_t type = mir_vec4_type(g->mu, size, false);
39✔
1054

1055
         mir_value_t result;
39✔
1056
         if (size <= 64)
39✔
1057
            result = mir_const_vec(g->mu, type, 0, 0);
27✔
1058
         else {
1059
            mir_type_t t_bit = mir_vec4_type(g->mu, 1, false);
12✔
1060
            mir_value_t zero = mir_const_vec(g->mu, t_bit, 0, 0);
12✔
1061
            result = mir_build_cast(g->mu, type, zero);
12✔
1062
         }
1063

1064
         mir_type_t t_offset = mir_offset_type(g->mu);
39✔
1065

1066
         for (int i = 0, pos = size; i < repeat; i++) {
273✔
1067
            for (int j = nparams - 1; j >= 0; j--) {
489✔
1068
               pos -= mir_get_size(g->mu, mir_get_type(g->mu, inputs[j]));
255✔
1069
               result = mir_build_insert(g->mu, inputs[j], result,
255✔
1070
                                         mir_const(g->mu, t_offset, pos));
1071
            }
1072
         }
1073

1074
         return result;
39✔
1075
      }
1076
   case V_PREFIX:
3✔
1077
      {
1078
         vlog_node_t target = vlog_target(v);
3✔
1079

1080
         mir_value_t prev = vlog_lower_rvalue(g, target);
3✔
1081
         mir_type_t type = mir_get_type(g->mu, prev);
3✔
1082
         mir_value_t one = mir_const_vec(g->mu, type, 1, 0);
3✔
1083
         mir_value_t inc =
3✔
1084
            mir_build_binary(g->mu, MIR_VEC_ADD, type, prev, one);
3✔
1085

1086
         // Must save/restore around blocking assignment
1087
         mir_value_t tmp = mir_add_var(g->mu, type, MIR_NULL_STAMP,
3✔
1088
                                       ident_uniq("prefix"), MIR_VAR_TEMP);
1089
         mir_build_store(g->mu, tmp, inc);
3✔
1090

1091
         vlog_assign_variable(g, target, inc);
3✔
1092

1093
         return mir_build_load(g->mu, tmp);
3✔
1094
      }
1095
   case V_POSTFIX:
12✔
1096
      {
1097
         vlog_node_t target = vlog_target(v);
12✔
1098

1099
         mir_value_t prev = vlog_lower_rvalue(g, target);
12✔
1100
         mir_type_t type = mir_get_type(g->mu, prev);
12✔
1101
         mir_value_t one = mir_const_vec(g->mu, type, 1, 0);
12✔
1102
         mir_value_t inc =
12✔
1103
            mir_build_binary(g->mu, MIR_VEC_ADD, type, prev, one);
12✔
1104

1105
         vlog_assign_variable(g, target, inc);
12✔
1106

1107
         return inc;
12✔
1108
      }
1109
   case V_COND_EXPR:
30✔
1110
      {
1111
         // See 1800-2023 section 11.4.11 for semantics
1112

1113
         // TODO: do not evaluate both sides
1114

1115
         mir_value_t value = vlog_lower_rvalue(g, vlog_value(v));
30✔
1116
         mir_value_t cmp = mir_build_test(g->mu, value);
30✔
1117
         mir_value_t left = vlog_lower_rvalue(g, vlog_left(v));
30✔
1118
         mir_value_t right = vlog_lower_rvalue(g, vlog_right(v));
30✔
1119

1120
         mir_type_t ltype = mir_get_type(g->mu, left);
30✔
1121
         mir_type_t rtype = mir_get_type(g->mu, right);
30✔
1122

1123
         unsigned size = MAX(mir_get_size(g->mu, ltype),
30✔
1124
                             mir_get_size(g->mu, rtype));
1125
         mir_type_t type = mir_vec4_type(g->mu, size, false);
30✔
1126

1127
         mir_value_t lcast = mir_build_cast(g->mu, type, left);
30✔
1128
         mir_value_t rcast = mir_build_cast(g->mu, type, right);
30✔
1129

1130
         return mir_build_select(g->mu, type, cmp, lcast, rcast);
30✔
1131
      }
1132
   case V_USER_FCALL:
54✔
1133
      {
1134
         vlog_node_t decl = vlog_ref(v);
54✔
1135
         ident_t func = ident_prefix(vlog_ident2(decl), vlog_ident(decl), '.');
54✔
1136

1137
         const int nparams = vlog_params(v);
54✔
1138
         mir_value_t *args LOCAL =
108✔
1139
            xmalloc_array(nparams + 1, sizeof(mir_value_t));
54✔
1140

1141
         args[0] = mir_build_context_upref(g->mu, 1);  // XXX
54✔
1142
         for (int i = 0; i < nparams; i++) {
147✔
1143
            mir_value_t value = vlog_lower_rvalue(g, vlog_param(v, i));
93✔
1144
            vlog_node_t dt = vlog_type(vlog_port(decl, i));
93✔
1145
            const type_info_t *ti = vlog_type_info(g, dt);
93✔
1146
            args[i + 1] = mir_build_cast(g->mu, ti->type, value);
93✔
1147
         }
1148

1149
         const type_info_t *ti = vlog_type_info(g, vlog_type(decl));
54✔
1150
         return mir_build_fcall(g->mu, func, ti->type, MIR_NULL_STAMP,
54✔
1151
                                args, nparams + 1);
1152
      }
1153
   case V_REAL:
3✔
1154
      {
1155
         mir_type_t t_double = mir_double_type(g->mu);
3✔
1156
         return mir_const_real(g->mu, t_double, vlog_dval(v));
3✔
1157
      }
1158
   case V_OP_ASSIGN:
30✔
1159
      return vlog_lower_operator_assignment(g, v);
30✔
1160
   case V_CLASS_NEW:
3✔
1161
      {
1162
         const type_info_t *ti = vlog_type_info(g, vlog_type(v));
3✔
1163
         mir_value_t context = mir_build_context_upref(g->mu, 0);  // XXX
3✔
1164
         return mir_build_protected_init(g->mu, ti->type, context,
3✔
1165
                                         MIR_NULL_VALUE, MIR_NULL_VALUE);
3✔
1166
      }
1167
   case V_MEMBER_REF:
48✔
1168
      {
1169
         const type_info_t *ti = vlog_type_info(g, vlog_type(vlog_ref(v)));
48✔
1170

1171
         mir_value_t context = vlog_lower_rvalue(g, vlog_value(v));
48✔
1172
         mir_value_t link = mir_build_link_var(g->mu, context,
48✔
1173
                                               vlog_ident(v), ti->type);
1174
         return mir_build_load(g->mu, link);
48✔
1175
      }
1176
   case V_NULL:
12✔
1177
      {
1178
         const type_info_t *ti = vlog_type_info(g, vlog_type(v));
12✔
1179
         return mir_build_null(g->mu, ti->type);
12✔
1180
      }
UNCOV
1181
   default:
×
1182
      CANNOT_HANDLE(v);
6,441✔
1183
   }
1184
}
1185

1186
static mir_value_t vlog_lower_time(vlog_gen_t *g, vlog_node_t v)
39✔
1187
{
1188
   assert(vlog_kind(v) == V_NUMBER);
39✔
1189

1190
   mir_type_t t_time = mir_time_type(g->mu);
39✔
1191
   number_t num = vlog_number(v);
39✔
1192

1193
   return mir_const(g->mu, t_time, number_integer(num));
39✔
1194
}
1195

1196
static mir_value_t vlog_or_triggers(vlog_gen_t *g, int n, ...)
243✔
1197
{
1198
   va_list ap;
243✔
1199
   va_start(ap, n);
243✔
1200

1201
   mir_value_t or = MIR_NULL_VALUE;
243✔
1202
   for (int i = 0; i < n; i++) {
729✔
1203
      mir_value_t t = va_arg(ap, mir_value_t);
486✔
1204
      if (mir_is_null(t))
486✔
1205
         continue;
159✔
1206
      else if (mir_is_null(or))
327✔
1207
         or = t;
243✔
1208
      else
1209
         or = mir_build_or_trigger(g->mu, or, t);
84✔
1210
   }
1211

1212
   va_end(ap);
243✔
1213
   return or;
243✔
1214
}
1215

1216
static void vlog_lower_edge_fn(mir_unit_t *mu, int edge)
33✔
1217
{
1218
   mir_type_t t_context = mir_context_type(mu, ident_new("dummy"));
33✔
1219
   mir_type_t t_bool = mir_bool_type(mu);
33✔
1220
   mir_type_t t_logic = mir_vec4_type(mu, 1, false);
33✔
1221
   mir_type_t t_net_value = mir_int_type(mu, 0, 255);
33✔
1222
   mir_type_t t_net_signal = mir_signal_type(mu, t_net_value);
33✔
1223

1224
   mir_set_result(mu, t_bool);
33✔
1225

1226
   mir_add_param(mu, t_context, MIR_NULL_STAMP, ident_new("context"));
33✔
1227
   mir_value_t nets = mir_add_param(mu, t_net_signal, MIR_NULL_STAMP,
33✔
1228
                                    ident_new("arg"));
1229

1230
   mir_value_t ptr = mir_build_resolved(mu, nets);
33✔
1231
   mir_value_t data = mir_build_load(mu, ptr);
33✔
1232
   mir_value_t rvalue = mir_build_pack(mu, t_logic, data);
33✔
1233

1234
   mir_value_t level = mir_const_vec(mu, t_logic, edge, 0);
33✔
1235
   mir_value_t cmp = mir_build_cmp(mu, MIR_CMP_EQ, rvalue, level);
33✔
1236
   mir_build_return(mu, cmp);
33✔
1237
}
33✔
1238

1239
static void vlog_lower_posedge_fn(mir_unit_t *mu, object_t *obj)
27✔
1240
{
1241
   vlog_lower_edge_fn(mu, 1);
27✔
1242
}
27✔
1243

1244
static void vlog_lower_negedge_fn(mir_unit_t *mu, object_t *obj)
6✔
1245
{
1246
   vlog_lower_edge_fn(mu, 0);
6✔
1247
}
6✔
1248

1249
static mir_value_t vlog_lower_trigger(vlog_gen_t *g, vlog_node_t v)
243✔
1250
{
1251
   const vlog_kind_t kind = vlog_kind(v);
432✔
1252
   switch (kind) {
432✔
1253
   case V_REF:
183✔
1254
   case V_HIER_REF:
1255
      {
1256
         switch (vlog_kind(vlog_ref(v))) {
183✔
1257
         case V_PORT_DECL:
183✔
1258
         case V_NET_DECL:
1259
         case V_VAR_DECL:
1260
            {
1261
               mir_type_t t_offset = mir_offset_type(g->mu);
183✔
1262

1263
               vlog_lvalue_t lvalue = vlog_lower_lvalue(g, v);
183✔
1264
               mir_value_t count = mir_const(g->mu, t_offset, lvalue.size);
183✔
1265

1266
               return mir_build_level_trigger(g->mu, lvalue.nets, count);
183✔
1267
            }
1268
         case V_PARAM_DECL:
×
1269
         case V_LOCALPARAM:
1270
            return MIR_NULL_VALUE;
×
1271
         default:
×
1272
            CANNOT_HANDLE(v);
×
1273
         }
1274
      }
1275
      break;
1276
   case V_BIT_SELECT:
6✔
1277
   case V_PART_SELECT:
1278
      {
1279
         mir_value_t trigger;
6✔
1280
         vlog_node_t prefix = vlog_longest_static_prefix(v);
6✔
1281
         if (prefix == v) {
6✔
1282
            mir_type_t t_offset = mir_offset_type(g->mu);
6✔
1283

1284
            vlog_lvalue_t lvalue = vlog_lower_lvalue(g, v);
6✔
1285

1286
            mir_value_t count = mir_const(g->mu, t_offset, lvalue.size);
6✔
1287

1288
            // XXX: check in range
1289
            mir_value_t nets =
6✔
1290
               mir_build_array_ref(g->mu, lvalue.nets, lvalue.offset);
6✔
1291

1292
            trigger = mir_build_level_trigger(g->mu, nets, count);
6✔
1293
         }
1294
         else
1295
            trigger = vlog_lower_trigger(g, prefix);
×
1296

1297
         if (kind == V_BIT_SELECT) {
6✔
1298
            const int nparams = vlog_params(v);
6✔
1299
            for (int i = 0; i < nparams; i++) {
18✔
1300
               mir_value_t p = vlog_lower_trigger(g, vlog_param(v, i));
12✔
1301
               trigger = vlog_or_triggers(g, 2, trigger, p);
12✔
1302
            }
1303
         }
1304
         else {
1305
            mir_value_t left = vlog_lower_trigger(g, vlog_left(v));
×
1306
            trigger = vlog_or_triggers(g, 2, trigger, left);
×
1307
         }
1308

1309
         return trigger;
6✔
1310
      }
1311
   case V_EVENT:
231✔
1312
      {
1313
         const v_event_kind_t kind = vlog_subkind(v);
231✔
1314
         if (kind == V_EVENT_LEVEL)
231✔
1315
            return vlog_lower_trigger(g, vlog_value(v));
189✔
1316
         else {
1317
            vlog_lvalue_t lvalue = vlog_lower_lvalue(g, vlog_value(v));
42✔
1318

1319
            ident_t func;
42✔
1320
            switch (kind) {
42✔
1321
            case V_EVENT_POSEDGE:
27✔
1322
               func = ident_new("__posedge");
27✔
1323
               mir_defer(mir_get_context(g->mu), func, NULL, MIR_UNIT_FUNCTION,
27✔
1324
                         vlog_lower_posedge_fn, NULL);
1325
               break;
27✔
1326
            case V_EVENT_NEGEDGE:
15✔
1327
               func = ident_new("__negedge");
15✔
1328
               mir_defer(mir_get_context(g->mu), func, NULL, MIR_UNIT_FUNCTION,
15✔
1329
                         vlog_lower_negedge_fn, NULL);
1330
               break;
15✔
1331
            default:
×
1332
               should_not_reach_here();
1333
            }
1334

1335
            mir_value_t context = mir_build_context_upref(g->mu, 0);
42✔
1336
            mir_value_t args[] = { context, lvalue.nets };
42✔
1337
            return mir_build_function_trigger(g->mu, func, args, 2);
42✔
1338
         }
1339
      }
1340
   case V_NUMBER:
12✔
1341
      return MIR_NULL_VALUE;
12✔
1342
   case V_BINARY:
×
1343
      {
1344
         mir_value_t left = vlog_lower_trigger(g, vlog_left(v));
×
1345
         mir_value_t right = vlog_lower_trigger(g, vlog_right(v));
×
1346

1347
         return vlog_or_triggers(g, 2, left, right);
×
1348
      }
1349
   case V_UNARY:
×
1350
      return vlog_lower_trigger(g, vlog_value(v));
×
1351
   case V_COND_EXPR:
×
1352
      {
1353
         mir_value_t value = vlog_lower_trigger(g, vlog_value(v));
×
1354
         mir_value_t left = vlog_lower_trigger(g, vlog_left(v));
×
1355
         mir_value_t right = vlog_lower_trigger(g, vlog_right(v));
×
1356

1357
         return vlog_or_triggers(g, 3, value, left, right);
×
1358
      }
1359
   case V_CONCAT:
×
1360
   case V_USER_FCALL:
1361
      {
1362
         mir_value_t trigger = MIR_NULL_VALUE;
×
1363
         const int nparams = vlog_params(v);
×
1364
         for (int i = 0; i < nparams; i++) {
×
1365
            mir_value_t p = vlog_lower_trigger(g, vlog_param(v, i));
×
1366
            trigger = vlog_or_triggers(g, 2, trigger, p);
×
1367
         }
1368

1369
         return trigger;
×
1370
      }
1371
   default:
×
1372
      CANNOT_HANDLE(v);
×
1373
   }
1374
}
1375

1376
static void vlog_lower_timing(vlog_gen_t *g, vlog_node_t v, bool is_static)
696✔
1377
{
1378
   vlog_node_t ctrl = vlog_value(v);
696✔
1379
   switch (vlog_kind(ctrl)) {
696✔
1380
   case V_DELAY_CONTROL:
546✔
1381
      {
1382
         mir_type_t t_time = mir_time_type(g->mu);
546✔
1383
         mir_value_t delay = vlog_lower_rvalue(g, vlog_value(ctrl));
546✔
1384
         mir_value_t cast = mir_build_cast(g->mu, t_time, delay);
546✔
1385

1386
         int64_t dconst;
546✔
1387
         if (mir_get_const(g->mu, cast, &dconst) && dconst == 0)
546✔
1388
            mir_build_sched_inactive(g->mu);
21✔
1389
         else
1390
            mir_build_sched_process(g->mu, cast);
525✔
1391

1392
         mir_block_t wait_bb = mir_add_block(g->mu);
546✔
1393
         mir_build_wait(g->mu, wait_bb);
546✔
1394

1395
         mir_set_cursor(g->mu, wait_bb, MIR_APPEND);
546✔
1396
      }
1397
      break;
546✔
1398
   case V_EVENT_CONTROL:
150✔
1399
      {
1400
         const int nparams = vlog_params(ctrl);
150✔
1401

1402
         mir_value_t trigger_var = MIR_NULL_VALUE;
150✔
1403
         if (!is_static) {
150✔
1404
            mir_value_t trigger = MIR_NULL_VALUE;
30✔
1405
            for (int i = 0; i < nparams; i++) {
75✔
1406
               mir_value_t p = vlog_lower_trigger(g, vlog_param(ctrl, i));
45✔
1407
               trigger = vlog_or_triggers(g, 2, trigger, p);
45✔
1408
            }
1409

1410
            if (!mir_is_null(trigger)) {
30✔
1411
               mir_type_t t_trigger = mir_trigger_type(g->mu);
30✔
1412
               trigger_var = mir_add_var(g->mu, t_trigger, MIR_NULL_STAMP,
30✔
1413
                                         ident_uniq("trigger"), 0);
1414
               mir_build_store(g->mu, trigger_var, trigger);
30✔
1415

1416
               mir_build_sched_event(g->mu, trigger, MIR_NULL_VALUE);
30✔
1417
            }
1418
         }
1419

1420
         mir_block_t wait_bb = mir_add_block(g->mu);
150✔
1421
         mir_build_wait(g->mu, wait_bb);
150✔
1422

1423
         mir_set_cursor(g->mu, wait_bb, MIR_APPEND);
150✔
1424

1425
         if (!mir_is_null(trigger_var)) {
150✔
1426
            mir_value_t trigger = mir_build_load(g->mu, trigger_var);
30✔
1427
            mir_build_clear_event(g->mu, trigger, MIR_NULL_VALUE);
30✔
1428
         }
1429
      }
1430
      break;
1431
   default:
×
1432
      CANNOT_HANDLE(ctrl);
×
1433
   }
1434

1435
   vlog_lower_stmts(g, v);
696✔
1436
}
696✔
1437

1438
static mir_value_t vlog_lower_default_value(vlog_gen_t *g,
36✔
1439
                                            const type_info_t *ti)
1440
{
1441
   assert(ti->size < 64);  // TODO
36✔
1442

1443
   switch (mir_get_class(g->mu, ti->type)) {
36✔
1444
   case MIR_TYPE_VEC2:
6✔
1445
      return mir_const_vec(g->mu, ti->type, 0, 0);
6✔
1446
   case MIR_TYPE_VEC4:
30✔
1447
      {
1448
         uint64_t mask = ~UINT64_C(0);
30✔
1449
         if (ti->size < 64) mask >>= 64 - ti->size;
30✔
1450

1451
         return mir_const_vec(g->mu, ti->type, mask, mask);
30✔
1452
      }
1453
   default:
×
1454
      should_not_reach_here();
1455
   }
1456
}
1457

1458
static void vlog_lower_blocking_assignment(vlog_gen_t *g, vlog_node_t v)
1,137✔
1459
{
1460
   if (vlog_has_delay(v)) {
1,137✔
1461
      vlog_node_t delay = vlog_delay(v);
24✔
1462
      assert(vlog_kind(delay) == V_DELAY_CONTROL);
24✔
1463

1464
      mir_build_sched_process(g->mu, vlog_lower_time(g, vlog_value(delay)));
24✔
1465

1466
      mir_block_t delay_bb = mir_add_block(g->mu);
24✔
1467
      mir_build_wait(g->mu, delay_bb);
24✔
1468

1469
      mir_set_cursor(g->mu, delay_bb, MIR_APPEND);
24✔
1470
   }
1471

1472
   mir_value_t value = vlog_lower_rvalue(g, vlog_value(v));
1,137✔
1473
   vlog_assign_variable(g, vlog_target(v), value);
1,137✔
1474
}
1,137✔
1475

1476
static void vlog_lower_non_blocking_assignment(vlog_gen_t *g, vlog_node_t v)
123✔
1477
{
1478
   vlog_node_t target = vlog_target(v);
123✔
1479

1480
   vlog_lvalue_t lvalue = vlog_lower_lvalue(g, target);
123✔
1481

1482
   // XXX: check in range
1483
   mir_value_t nets = mir_build_array_ref(g->mu, lvalue.nets, lvalue.offset);
123✔
1484

1485
   mir_value_t value = vlog_lower_rvalue(g, vlog_value(v));
123✔
1486
   assert(mir_is_vector(g->mu, value));
123✔
1487

1488
   mir_type_t t_offset = mir_offset_type(g->mu);
123✔
1489
   mir_type_t t_vec = mir_vec4_type(g->mu, lvalue.size, false);
123✔
1490

1491
   mir_value_t resize = mir_build_cast(g->mu, t_vec, value);
123✔
1492
   mir_value_t count = mir_const(g->mu, t_offset, lvalue.size);
123✔
1493

1494
   mir_value_t tmp = MIR_NULL_VALUE;
123✔
1495
   if (lvalue.size > 1) {
123✔
1496
      mir_type_t t_elem = mir_logic_type(g->mu);
48✔
1497
      mir_type_t t_array = mir_carray_type(g->mu, lvalue.size, t_elem);
48✔
1498
      tmp = vlog_get_temp(g, t_array);
48✔
1499
   }
1500

1501
   const uint8_t strength = vlog_is_net(target) ? ST_STRONG : 0;
123✔
1502
   mir_value_t unpacked = mir_build_unpack(g->mu, resize, strength, tmp);
123✔
1503

1504
   mir_type_t t_time = mir_time_type(g->mu);
123✔
1505

1506
   mir_value_t after;
123✔
1507
   if (vlog_has_delay(v)) {
123✔
1508
      vlog_node_t delay = vlog_delay(v);
12✔
1509
      assert(vlog_kind(delay) == V_DELAY_CONTROL);
12✔
1510

1511
      after = vlog_lower_time(g, vlog_value(delay));
12✔
1512
   }
1513
   else
1514
      after = mir_const(g->mu, t_time, 0);
111✔
1515

1516
   mir_build_sched_deposit(g->mu, nets, count, unpacked, after);
123✔
1517
}
123✔
1518

1519
static void vlog_lower_if(vlog_gen_t *g, vlog_node_t v)
525✔
1520
{
1521
   mir_block_t exit_bb = MIR_NULL_BLOCK;
525✔
1522

1523
   const int nconds = vlog_conds(v);
525✔
1524
   for (int i = 0; i < nconds; i++) {
1,059✔
1525
      vlog_node_t c = vlog_cond(v, i);
639✔
1526
      mir_block_t next_bb = MIR_NULL_BLOCK;
639✔
1527

1528
      if (vlog_has_value(c)) {
639✔
1529
         mir_value_t value = vlog_lower_rvalue(g, vlog_value(c)), cmp = value;
534✔
1530
         if (mir_is_vector(g->mu, value))
534✔
1531
            cmp = mir_build_test(g->mu, value);
528✔
1532

1533
         mir_block_t btrue = mir_add_block(g->mu);
534✔
1534

1535
         if (i == nconds - 1) {
534✔
1536
            if (mir_is_null(exit_bb))
420✔
1537
               exit_bb = mir_add_block(g->mu);
414✔
1538
            next_bb = exit_bb;
420✔
1539
         }
1540
         else
1541
            next_bb = mir_add_block(g->mu);
114✔
1542

1543
         mir_build_cond(g->mu, cmp, btrue, next_bb);
534✔
1544

1545
         mir_set_cursor(g->mu, btrue, MIR_APPEND);
534✔
1546
      }
1547

1548
      vlog_lower_stmts(g, c);
639✔
1549

1550
      if (!mir_block_finished(g->mu, MIR_NULL_BLOCK)) {
639✔
1551
         if (mir_is_null(exit_bb))
639✔
1552
            exit_bb = mir_add_block(g->mu);
111✔
1553
         mir_build_jump(g->mu, exit_bb);
639✔
1554
      }
1555

1556
      if (mir_is_null(next_bb))
639✔
1557
         break;
1558

1559
      mir_set_cursor(g->mu, next_bb, MIR_APPEND);
534✔
1560
   }
1561

1562
   if (!mir_is_null(exit_bb))
525✔
1563
      mir_set_cursor(g->mu, exit_bb, MIR_APPEND);
525✔
1564
}
525✔
1565

1566
static void vlog_lower_forever(vlog_gen_t *g, vlog_node_t v)
3✔
1567
{
1568
   mir_block_t body_bb = mir_add_block(g->mu);
3✔
1569
   mir_build_jump(g->mu, body_bb);
3✔
1570

1571
   mir_set_cursor(g->mu, body_bb, MIR_APPEND);
3✔
1572

1573
   vlog_lower_stmts(g, v);
3✔
1574

1575
   mir_build_jump(g->mu, body_bb);
3✔
1576
}
3✔
1577

1578
static void vlog_lower_repeat(vlog_gen_t *g, vlog_node_t v)
3✔
1579
{
1580
   mir_type_t t_offset = mir_offset_type(g->mu);
3✔
1581
   mir_value_t i_var = mir_add_var(g->mu, t_offset, MIR_NULL_STAMP,
3✔
1582
                                   ident_new("i"), MIR_VAR_TEMP);
1583
   mir_value_t zero = mir_const(g->mu, t_offset, 0);
3✔
1584
   mir_build_store(g->mu, i_var, zero);
3✔
1585

1586
   mir_value_t rvalue = vlog_lower_rvalue(g, vlog_value(v));
3✔
1587
   mir_value_t limit = mir_build_cast(g->mu, t_offset, rvalue);
3✔
1588
   mir_value_t enter = mir_build_cmp(g->mu, MIR_CMP_LT, zero, limit);
3✔
1589

1590
   mir_block_t body_bb = mir_add_block(g->mu);
3✔
1591
   mir_block_t cont_bb = mir_add_block(g->mu);
3✔
1592
   mir_build_cond(g->mu, enter, body_bb, cont_bb);
3✔
1593

1594
   mir_set_cursor(g->mu, body_bb, MIR_APPEND);
3✔
1595

1596
   vlog_lower_stmts(g, v);
3✔
1597

1598
   if (!mir_block_finished(g->mu, MIR_NULL_BLOCK)) {
3✔
1599
      mir_value_t i_val = mir_build_load(g->mu, i_var);
3✔
1600
      mir_value_t one = mir_const(g->mu, t_offset, 1);
3✔
1601
      mir_value_t next = mir_build_add(g->mu, t_offset, i_val, one);
3✔
1602
      mir_build_store(g->mu, i_var, next);
3✔
1603

1604
      mir_value_t done = mir_build_cmp(g->mu, MIR_CMP_LT, next, limit);
3✔
1605
      mir_build_cond(g->mu, done, body_bb, cont_bb);
3✔
1606
   }
1607

1608
   mir_set_cursor(g->mu, cont_bb, MIR_APPEND);
3✔
1609
}
3✔
1610

1611
static void vlog_lower_while(vlog_gen_t *g, vlog_node_t v)
3✔
1612
{
1613
   mir_block_t test_bb = mir_add_block(g->mu);
3✔
1614
   mir_block_t body_bb = mir_add_block(g->mu);
3✔
1615
   mir_block_t cont_bb = mir_add_block(g->mu);
3✔
1616

1617
   mir_build_jump(g->mu, test_bb);
3✔
1618

1619
   mir_set_cursor(g->mu, test_bb, MIR_APPEND);
3✔
1620

1621
   mir_value_t rvalue = vlog_lower_rvalue(g, vlog_value(v));
3✔
1622
   mir_value_t test = mir_build_test(g->mu, rvalue);
3✔
1623
   mir_build_cond(g->mu, test, body_bb, cont_bb);
3✔
1624

1625
   mir_set_cursor(g->mu, body_bb, MIR_APPEND);
3✔
1626

1627
   vlog_lower_stmts(g, v);
3✔
1628

1629
   if (!mir_block_finished(g->mu, MIR_NULL_BLOCK))
3✔
1630
      mir_build_jump(g->mu, test_bb);
3✔
1631

1632
   mir_set_cursor(g->mu, cont_bb, MIR_APPEND);
3✔
1633
}
3✔
1634

1635
static void vlog_lower_for_loop(vlog_gen_t *g, vlog_node_t v)
39✔
1636
{
1637
   mir_comment(g->mu, "Begin for loop");
39✔
1638

1639
   vlog_node_t init = vlog_left(v);
39✔
1640
   assert(vlog_kind(init) == V_FOR_INIT);
39✔
1641

1642
   assert(vlog_decls(init) == 0);   // TODO
39✔
1643

1644
   vlog_lower_stmts(g, init);
39✔
1645

1646
   mir_block_t body_bb = mir_add_block(g->mu);
39✔
1647
   mir_block_t step_bb = mir_add_block(g->mu);
39✔
1648
   mir_block_t test_bb = mir_add_block(g->mu);
39✔
1649
   mir_block_t exit_bb = mir_add_block(g->mu);
39✔
1650

1651
   mir_build_jump(g->mu, test_bb);
39✔
1652

1653
   mir_set_cursor(g->mu, test_bb, MIR_APPEND);
39✔
1654

1655
   mir_comment(g->mu, "For loop test");
39✔
1656

1657
   mir_value_t test = vlog_lower_rvalue(g, vlog_value(v));
39✔
1658
   assert(mir_is_vector(g->mu, test));
39✔
1659

1660
   mir_value_t zero = mir_const_vec(g->mu, mir_get_type(g->mu, test), 0, 0);
39✔
1661
   mir_value_t cmp = mir_build_cmp(g->mu, MIR_CMP_NEQ, test, zero);
39✔
1662
   mir_build_cond(g->mu, cmp, body_bb, exit_bb);
39✔
1663

1664
   mir_set_cursor(g->mu, body_bb, MIR_APPEND);
39✔
1665

1666
   mir_comment(g->mu, "For loop body");
39✔
1667

1668
   vlog_lower_stmts(g, v);
39✔
1669

1670
   if (!mir_block_finished(g->mu, MIR_NULL_BLOCK))
39✔
1671
      mir_build_jump(g->mu, step_bb);
39✔
1672

1673
   mir_set_cursor(g->mu, step_bb, MIR_APPEND);
39✔
1674

1675
   mir_comment(g->mu, "For loop step");
39✔
1676

1677
   vlog_node_t step = vlog_right(v);
39✔
1678
   assert(vlog_kind(step) == V_FOR_STEP);
39✔
1679

1680
   const int nstmts = vlog_stmts(step);
39✔
1681
   for (int i = 0; i < nstmts; i++)
78✔
1682
      vlog_lower_rvalue(g, vlog_stmt(step, i));
39✔
1683

1684
   mir_build_jump(g->mu, test_bb);
39✔
1685

1686
   mir_set_cursor(g->mu, exit_bb, MIR_APPEND);
39✔
1687

1688
   mir_comment(g->mu, "End for loop");
39✔
1689
}
39✔
1690

1691
static void vlog_lower_case(vlog_gen_t *g, vlog_node_t v)
6✔
1692
{
1693
   mir_comment(g->mu, "Begin case statement");
6✔
1694

1695
   mir_value_t value = vlog_lower_rvalue(g, vlog_value(v));
6✔
1696
   mir_type_t type = mir_get_type(g->mu, value);
6✔
1697

1698
   // TODO: use a parallel case for small integer types
1699

1700
   const int nitems = vlog_stmts(v);
6✔
1701
   mir_block_t *blocks LOCAL = xmalloc_array(nitems, sizeof(mir_block_t));
12✔
1702

1703
   mir_type_t t_logic = mir_vec4_type(g->mu, 1, false);
6✔
1704
   mir_value_t zero = mir_const_vec(g->mu, t_logic, 0, 0);
6✔
1705

1706
   const mir_vec_op_t op = vlog_subkind(v) == V_CASE_NORMAL
6✔
1707
      ? MIR_VEC_CASE_EQ : MIR_VEC_CASEX_EQ;
6✔
1708

1709
   for (int i = 0; i < nitems; i++) {
42✔
1710
      vlog_node_t item = vlog_stmt(v, i);
36✔
1711
      assert(vlog_kind(item) == V_CASE_ITEM);
36✔
1712

1713
      blocks[i] = mir_add_block(g->mu);
36✔
1714

1715
      mir_block_t else_bb = mir_add_block(g->mu);
36✔
1716

1717
      mir_value_t comb = MIR_NULL_VALUE;
36✔
1718
      const int nparams = vlog_params(item);
36✔
1719
      for (int j = 0; j < nparams; j++) {
69✔
1720
         mir_value_t test = vlog_lower_rvalue(g, vlog_param(item, j));
33✔
1721
         mir_value_t cast = mir_build_cast(g->mu, type, test);
33✔
1722
         mir_value_t case_eq = mir_build_binary(g->mu, op, type, cast, value);
33✔
1723
         mir_value_t cmp = mir_build_cmp(g->mu, MIR_CMP_NEQ, case_eq, zero);
33✔
1724

1725
         if (mir_is_null(comb))
33✔
1726
            comb = cmp;
33✔
1727
         else
1728
            comb = mir_build_or(g->mu, comb, cmp);
×
1729
      }
1730

1731
      if (mir_is_null(comb))
36✔
1732
         mir_build_jump(g->mu, blocks[i]);
3✔
1733
      else
1734
         mir_build_cond(g->mu, comb, blocks[i], else_bb);
33✔
1735

1736
      mir_set_cursor(g->mu, else_bb, MIR_APPEND);
36✔
1737
   }
1738

1739
   mir_block_t exit_bb = mir_get_cursor(g->mu, NULL);
6✔
1740

1741
   for (int i = 0; i < nitems; i++) {
42✔
1742
      vlog_node_t item = vlog_stmt(v, i);
36✔
1743
      assert(vlog_kind(item) == V_CASE_ITEM);
36✔
1744

1745
      mir_set_cursor(g->mu, blocks[i], MIR_APPEND);
36✔
1746
      vlog_lower_stmts(g, item);
36✔
1747

1748
      if (!mir_block_finished(g->mu, MIR_NULL_BLOCK))
36✔
1749
         mir_build_jump(g->mu, exit_bb);
36✔
1750
   }
1751

1752
   mir_set_cursor(g->mu, exit_bb, MIR_APPEND);
6✔
1753

1754
   mir_comment(g->mu, "End case statement");
6✔
1755
}
6✔
1756

1757
static void vlog_lower_return(vlog_gen_t *g, vlog_node_t v)
×
1758
{
1759
   mir_value_t result = MIR_NULL_VALUE;
×
1760
   if (vlog_has_value(v)) {
×
1761
      mir_value_t value = vlog_lower_rvalue(g, vlog_value(v));
×
1762

1763
      const type_info_t *ti = vlog_type_info(g, vlog_type(vlog_ref(v)));
×
1764
      result = mir_build_cast(g->mu, ti->type, value);
×
1765
   }
1766

1767
   mir_build_return(g->mu, result);
×
1768
}
×
1769

1770
static void vlog_lower_stmts(vlog_gen_t *g, vlog_node_t v)
2,436✔
1771
{
1772
   const int nstmts = vlog_stmts(v);
2,436✔
1773
   for (int i = 0; i < nstmts; i++) {
6,690✔
1774
      vlog_node_t s = vlog_stmt(v, i);
4,254✔
1775
      mir_set_loc(g->mu, vlog_loc(s));
4,254✔
1776

1777
      switch (vlog_kind(s)) {
4,254✔
1778
      case V_TIMING:
576✔
1779
         vlog_lower_timing(g, s, false);
576✔
1780
         break;
576✔
1781
      case V_BASSIGN:
1,137✔
1782
         vlog_lower_blocking_assignment(g, s);
1,137✔
1783
         break;
1,137✔
1784
      case V_NBASSIGN:
123✔
1785
         vlog_lower_non_blocking_assignment(g, s);
123✔
1786
         break;
123✔
1787
      case V_OP_ASSIGN:
45✔
1788
         vlog_lower_operator_assignment(g, s);
45✔
1789
         break;
45✔
1790
      case V_BLOCK:
666✔
1791
         vlog_lower_stmts(g, s);
666✔
1792
         break;
666✔
1793
      case V_SYS_TCALL:
1,125✔
1794
         vlog_lower_sys_tfcall(g, s);
1,125✔
1795
         break;
1,125✔
1796
      case V_IF:
525✔
1797
         vlog_lower_if(g, s);
525✔
1798
         break;
525✔
1799
      case V_FOREVER:
3✔
1800
         vlog_lower_forever(g, s);
3✔
1801
         break;
3✔
1802
      case V_REPEAT:
3✔
1803
         vlog_lower_repeat(g, s);
3✔
1804
         break;
3✔
1805
      case V_WHILE:
3✔
1806
         vlog_lower_while(g, s);
3✔
1807
         break;
3✔
1808
      case V_FOR_LOOP:
39✔
1809
         vlog_lower_for_loop(g, s);
39✔
1810
         break;
39✔
1811
      case V_CASE:
6✔
1812
         vlog_lower_case(g, s);
6✔
1813
         break;
6✔
1814
      case V_POSTFIX:
3✔
1815
         vlog_lower_rvalue(g, s);
3✔
1816
         break;
3✔
1817
      case V_RETURN:
×
1818
         vlog_lower_return(g, s);
×
1819
         return;
×
1820
      default:
×
1821
         CANNOT_HANDLE(s);
4,254✔
1822
      }
1823
   }
1824
}
1825

1826
static void vlog_lower_driver(vlog_gen_t *g, vlog_node_t v)
462✔
1827
{
1828
   if (vlog_kind(v) == V_CONCAT) {
462✔
1829
      const int nparams = vlog_params(v);
6✔
1830
      for (int i = 0; i < nparams; i++)
21✔
1831
         vlog_lower_driver(g, vlog_param(v, i));
15✔
1832
   }
1833
   else {
1834
      mir_type_t t_offset = mir_offset_type(g->mu);
456✔
1835

1836
      vlog_node_t prefix = vlog_longest_static_prefix(v);
456✔
1837

1838
      vlog_lvalue_t target = vlog_lower_lvalue(g, prefix);
456✔
1839

1840
      // XXX: check in range
1841
      mir_value_t nets = mir_build_array_ref(g->mu, target.nets, target.offset);
456✔
1842

1843
      int total_size = target.size;
456✔
1844
      if (vlog_kind(prefix) == V_REF)
456✔
1845
         total_size *= vlog_size(vlog_ref(prefix));
312✔
1846

1847
      mir_value_t count = mir_const(g->mu, t_offset, total_size);
456✔
1848
      mir_build_drive_signal(g->mu, nets, count);
456✔
1849
   }
1850
}
462✔
1851

1852
static void vlog_lower_always(vlog_gen_t *g, vlog_node_t v)
147✔
1853
{
1854
   mir_block_t start_bb = mir_add_block(g->mu);
147✔
1855
   assert(start_bb.id == 1);
147✔
1856

1857
   vlog_node_t timing = NULL, s0 = vlog_stmt(v, 0);
147✔
1858
   if (vlog_kind(s0) == V_TIMING) {
147✔
1859
      timing = s0;
126✔
1860

1861
      vlog_node_t ctrl = vlog_value(timing);
126✔
1862
      if (vlog_kind(ctrl) == V_EVENT_CONTROL) {
126✔
1863
         mir_value_t trigger = MIR_NULL_VALUE;
120✔
1864
         const int nparams = vlog_params(ctrl);
120✔
1865
         for (int i = 0; i < nparams; i++) {
306✔
1866
            mir_value_t t = vlog_lower_trigger(g, vlog_param(ctrl, i));
186✔
1867
            trigger = vlog_or_triggers(g, 2, trigger, t);
186✔
1868
         }
1869

1870
         if (!mir_is_null(trigger))
120✔
1871
            mir_build_sched_event(g->mu, trigger, MIR_NULL_VALUE);
117✔
1872
      }
1873
      else
1874
         timing = NULL;
1875
   }
1876

1877
   mir_build_return(g->mu, MIR_NULL_VALUE);
147✔
1878

1879
   mir_set_cursor(g->mu, start_bb, MIR_APPEND);
147✔
1880

1881
   if (timing != NULL)
147✔
1882
      vlog_lower_timing(g, timing, true);
120✔
1883
   else
1884
      vlog_lower_stmts(g, v);
27✔
1885

1886
   if (!mir_block_finished(g->mu, MIR_NULL_BLOCK))
147✔
1887
      mir_build_jump(g->mu, start_bb);
147✔
1888
}
147✔
1889

1890
static void vlog_lower_initial(vlog_gen_t *g, vlog_node_t v)
243✔
1891
{
1892
   mir_block_t start_bb = mir_add_block(g->mu);
243✔
1893
   assert(start_bb.id == 1);
243✔
1894

1895
   mir_build_return(g->mu, MIR_NULL_VALUE);
243✔
1896

1897
   mir_set_cursor(g->mu, start_bb, MIR_APPEND);
243✔
1898

1899
   vlog_lower_stmts(g, v);
243✔
1900

1901
   if (!mir_block_finished(g->mu, MIR_NULL_BLOCK))
243✔
1902
      mir_build_return(g->mu, MIR_NULL_VALUE);
240✔
1903
}
243✔
1904

1905
static void vlog_lower_sensitivity(vlog_gen_t *g, vlog_node_t v)
681✔
1906
{
1907
   const vlog_kind_t kind = vlog_kind(v);
804✔
1908
   switch (kind) {
804✔
1909
   case V_REF:
384✔
1910
   case V_HIER_REF:
1911
      {
1912
         switch (vlog_kind(vlog_ref(v))) {
384✔
1913
         case V_PORT_DECL:
384✔
1914
         case V_NET_DECL:
1915
         case V_VAR_DECL:
1916
            {
1917
               mir_type_t t_offset = mir_offset_type(g->mu);
384✔
1918

1919
               vlog_lvalue_t lvalue = vlog_lower_lvalue(g, v);
384✔
1920
               mir_value_t count = mir_const(g->mu, t_offset, lvalue.size);
384✔
1921

1922
               mir_build_sched_event(g->mu, lvalue.nets, count);
384✔
1923
            }
1924
            break;
384✔
1925
         case V_PARAM_DECL:
1926
         case V_LOCALPARAM:
1927
            break;
1928
         default:
×
1929
            CANNOT_HANDLE(v);
×
1930
         }
1931
      }
1932
      break;
1933
   case V_BIT_SELECT:
63✔
1934
   case V_PART_SELECT:
1935
      {
1936
         vlog_node_t prefix = vlog_longest_static_prefix(v);
63✔
1937
         if (prefix == v) {
63✔
1938
            mir_type_t t_offset = mir_offset_type(g->mu);
60✔
1939

1940
            vlog_lvalue_t lvalue = vlog_lower_lvalue(g, v);
60✔
1941

1942
            mir_value_t count = mir_const(g->mu, t_offset, lvalue.size);
60✔
1943

1944
            // XXX: check in range
1945
            mir_value_t nets =
60✔
1946
               mir_build_array_ref(g->mu, lvalue.nets, lvalue.offset);
60✔
1947

1948
            mir_build_sched_event(g->mu, nets, count);
60✔
1949
         }
1950
         else
1951
            vlog_lower_sensitivity(g, prefix);
3✔
1952

1953
         if (kind == V_BIT_SELECT) {
63✔
1954
            const int nparams = vlog_params(v);
54✔
1955
            for (int i = 0; i < nparams; i++)
108✔
1956
               vlog_lower_sensitivity(g, vlog_param(v, i));
54✔
1957
         }
1958
         else
1959
            vlog_lower_sensitivity(g, vlog_left(v));
9✔
1960
      }
1961
      break;
1962
   case V_NUMBER:
1963
      break;
1964
   case V_BINARY:
78✔
1965
      vlog_lower_sensitivity(g, vlog_left(v));
78✔
1966
      vlog_lower_sensitivity(g, vlog_right(v));
78✔
1967
      break;
78✔
1968
   case V_UNARY:
12✔
1969
      vlog_lower_sensitivity(g, vlog_value(v));
12✔
1970
      break;
12✔
1971
   case V_COND_EXPR:
24✔
1972
      vlog_lower_sensitivity(g, vlog_value(v));
24✔
1973
      vlog_lower_sensitivity(g, vlog_left(v));
24✔
1974
      vlog_lower_sensitivity(g, vlog_right(v));
24✔
1975
      break;
24✔
1976
   case V_CONCAT:
24✔
1977
   case V_USER_FCALL:
1978
   case V_SYS_FCALL:
1979
      {
1980
         const int nparams = vlog_params(v);
24✔
1981
         for (int i = 0; i < nparams; i++)
57✔
1982
            vlog_lower_sensitivity(g, vlog_param(v, i));
33✔
1983
      }
1984
      break;
1985
   default:
×
1986
      CANNOT_HANDLE(v);
×
1987
   }
1988
}
681✔
1989

1990
static void vlog_lower_continuous_assign(vlog_gen_t *g, vlog_node_t v)
387✔
1991
{
1992
   mir_block_t start_bb = mir_add_block(g->mu);
387✔
1993
   assert(start_bb.id == 1);
387✔
1994

1995
   vlog_lower_driver(g, vlog_target(v));
387✔
1996

1997
   vlog_lower_sensitivity(g, vlog_value(v));
387✔
1998

1999
   mir_build_return(g->mu, MIR_NULL_VALUE);
387✔
2000

2001
   mir_set_cursor(g->mu, start_bb, MIR_APPEND);
387✔
2002

2003
   vlog_node_t target = vlog_target(v);
387✔
2004

2005
   unsigned nlvalues = 1, targetsz = 0;
387✔
2006
   vlog_lvalue_t lvalue1, *lvalues = &lvalue1;
387✔
2007
   if (vlog_kind(target) == V_CONCAT) {
387✔
2008
      const int nparams = nlvalues = vlog_params(target);
6✔
2009
      lvalues = xmalloc_array(nparams, sizeof(vlog_lvalue_t));
6✔
2010
      for (int i = 0; i < nparams; i++) {
21✔
2011
         lvalues[i] = vlog_lower_lvalue(g, vlog_param(target, i));
15✔
2012
         targetsz += lvalues[i].size;
15✔
2013
      }
2014
   }
2015
   else {
2016
      lvalue1 = vlog_lower_lvalue(g, target);
381✔
2017
      targetsz = lvalue1.size;
381✔
2018
   }
2019

2020
   mir_value_t value = vlog_lower_rvalue(g, vlog_value(v));
387✔
2021
   assert(mir_is_vector(g->mu, value));
387✔
2022

2023
   mir_type_t t_vec = mir_vec4_type(g->mu, targetsz, false);
387✔
2024
   mir_value_t resize = mir_build_cast(g->mu, t_vec, value);
387✔
2025

2026
   mir_value_t tmp = MIR_NULL_VALUE;
387✔
2027
   if (targetsz != 1) {
387✔
2028
      mir_type_t t_elem = mir_logic_type(g->mu);
177✔
2029
      mir_type_t t_array = mir_carray_type(g->mu, targetsz, t_elem);
177✔
2030
      tmp = vlog_get_temp(g, t_array);
177✔
2031
   }
2032

2033
   mir_type_t t_offset = mir_offset_type(g->mu);
387✔
2034

2035
   mir_value_t unpacked = mir_build_unpack(g->mu, resize, ST_STRONG, tmp);
387✔
2036

2037
   for (int i = 0, offset = 0; i < nlvalues; offset += lvalues[i].size, i++) {
783✔
2038
      // XXX: check in range
2039
      mir_value_t nets = mir_build_array_ref(g->mu, lvalues[i].nets,
396✔
2040
                                             lvalues[i].offset);
396✔
2041

2042
      mir_value_t count = mir_const(g->mu, t_offset, lvalues[i].size);
396✔
2043

2044
      mir_value_t src = unpacked;
396✔
2045
      if (offset > 0) {
396✔
2046
         mir_value_t pos = mir_const(g->mu, t_offset, offset);
9✔
2047
         src = mir_build_array_ref(g->mu, unpacked, pos);
9✔
2048
      }
2049

2050
      if (vlog_has_delay(v)) {
396✔
2051
         vlog_node_t delay = vlog_delay(v);
3✔
2052
         assert(vlog_kind(delay) == V_DELAY_CONTROL);
3✔
2053

2054
         mir_value_t after = vlog_lower_time(g, vlog_value(delay));
3✔
2055
         mir_build_sched_waveform(g->mu, nets, count, src, after, after);
3✔
2056
      }
2057
      else
2058
         mir_build_put_driver(g->mu, nets, count, src);
393✔
2059
   }
2060

2061
   mir_build_wait(g->mu, start_bb);
387✔
2062

2063
   if (lvalues != &lvalue1)
387✔
2064
      free(lvalues);
6✔
2065
}
387✔
2066

2067
static void vlog_lower_gate_inst(vlog_gen_t *g, vlog_node_t v)
60✔
2068
{
2069
   mir_block_t start_bb = mir_add_block(g->mu);
60✔
2070
   assert(start_bb.id == 1);
60✔
2071

2072
   vlog_lower_driver(g, vlog_target(v));
60✔
2073

2074
   mir_type_t t_offset = mir_offset_type(g->mu);
60✔
2075
   mir_type_t t_time = mir_time_type(g->mu);
60✔
2076
   mir_type_t t_logic = mir_vec4_type(g->mu, 1, false);
60✔
2077

2078
   const int nparams = vlog_params(v);
60✔
2079
   int first_term = 0;
60✔
2080
   for (int i = 0; i < nparams; i++) {
156✔
2081
      vlog_node_t p = vlog_param(v, i);
96✔
2082
      if (vlog_kind(p) == V_STRENGTH)
96✔
2083
         first_term = i + 1;
18✔
2084
      else
2085
         vlog_lower_sensitivity(g, p);
78✔
2086
   }
2087

2088
   mir_build_return(g->mu, MIR_NULL_VALUE);
60✔
2089

2090
   mir_set_cursor(g->mu, start_bb, MIR_APPEND);
60✔
2091

2092
   bool negate = false;
60✔
2093
   uint8_t strength = ST_STRONG;
60✔
2094
   mir_value_t value = MIR_NULL_VALUE;
60✔
2095
   const vlog_gate_kind_t kind = vlog_subkind(v);
60✔
2096
   switch (kind) {
60✔
2097
   case V_GATE_PULLUP:
18✔
2098
   case V_GATE_PULLDOWN:
2099
      strength = vlog_subkind(vlog_param(v, 0));
18✔
2100
      value = mir_const_vec(g->mu, t_logic, kind == V_GATE_PULLUP, 0);
18✔
2101
      break;
18✔
2102

2103
   case V_GATE_NAND:
3✔
2104
   case V_GATE_NOR:
2105
   case V_GATE_XNOR:
2106
      negate = true;
3✔
2107
   case V_GATE_AND:
36✔
2108
   case V_GATE_OR:
2109
   case V_GATE_XOR:
2110
      {
2111
         static const mir_vec_op_t op_map[] = {
36✔
2112
            [V_GATE_AND] = MIR_VEC_BIT_AND,
2113
            [V_GATE_NAND] = MIR_VEC_BIT_AND,
2114
            [V_GATE_OR] = MIR_VEC_BIT_OR,
2115
            [V_GATE_NOR] = MIR_VEC_BIT_OR,
2116
            [V_GATE_XOR] = MIR_VEC_BIT_XOR,
2117
            [V_GATE_XNOR] = MIR_VEC_BIT_XOR,
2118
         };
2119

2120
         value = vlog_lower_rvalue(g, vlog_param(v, first_term));
36✔
2121

2122
         const int nelems = nparams - first_term;
36✔
2123
         for (int i = 1; i < nelems; i++) {
72✔
2124
            vlog_node_t p = vlog_param(v, first_term + i);
36✔
2125
            mir_value_t arg = vlog_lower_rvalue(g, p);
36✔
2126
            value = mir_build_binary(g->mu, op_map[kind], t_logic, value, arg);
36✔
2127
         }
2128

2129
         if (negate)
36✔
2130
            value = mir_build_unary(g->mu, MIR_VEC_BIT_NOT, t_logic, value);
3✔
2131
      }
2132
      break;
2133

2134
   case V_GATE_NOT:
3✔
2135
      {
2136
         mir_value_t input = vlog_lower_rvalue(g, vlog_param(v, nparams - 1));
3✔
2137
         value = mir_build_unary(g->mu, MIR_VEC_BIT_NOT, t_logic, input);
3✔
2138
      }
2139
      break;
3✔
2140

2141
   case V_GATE_BUF:
3✔
2142
      {
2143
         // Invert twice for correct X/Z behaviour
2144
         mir_value_t input = vlog_lower_rvalue(g, vlog_param(v, nparams - 1));
3✔
2145
         value = mir_build_unary(g->mu, MIR_VEC_BIT_NOT, t_logic, input);
3✔
2146
         value = mir_build_unary(g->mu, MIR_VEC_BIT_NOT, t_logic, value);
3✔
2147
      }
2148
      break;
3✔
2149

2150
   default:
×
2151
      CANNOT_HANDLE(v);
×
2152
   }
2153

2154
   mir_value_t unpacked =
60✔
2155
      mir_build_unpack(g->mu, value, strength, MIR_NULL_VALUE);
60✔
2156

2157
   mir_value_t reject = mir_const(g->mu, t_time, 0);
60✔
2158
   mir_value_t after = mir_const(g->mu, t_time, 0);
60✔
2159

2160
   vlog_lvalue_t lvalue = vlog_lower_lvalue(g, vlog_target(v));
60✔
2161
   mir_value_t count = mir_const(g->mu, t_offset, lvalue.size);
60✔
2162

2163
   // XXX: check in range
2164
   mir_value_t nets = mir_build_array_ref(g->mu, lvalue.nets, lvalue.offset);
60✔
2165

2166
   mir_build_sched_waveform(g->mu, nets, count, unpacked, reject, after);
60✔
2167
   mir_build_wait(g->mu, start_bb);
60✔
2168
}
60✔
2169

2170
static void vlog_lower_cleanup(vlog_gen_t *g)
1,301✔
2171
{
2172
   if (g->temps != NULL)
1,301✔
2173
      ihash_free(g->temps);
387✔
2174
}
1,301✔
2175

2176
void vlog_lower_deferred(mir_unit_t *mu, object_t *obj)
837✔
2177
{
2178
   vlog_node_t v = vlog_from_object(obj);
837✔
2179
   assert(v != NULL);
837✔
2180

2181
   vlog_gen_t g = {
837✔
2182
      .mu = mu,
2183
   };
2184

2185
   switch (vlog_kind(v)) {
837✔
2186
   case V_ALWAYS:
147✔
2187
      vlog_lower_always(&g, v);
147✔
2188
      break;
147✔
2189
   case V_INITIAL:
243✔
2190
      vlog_lower_initial(&g, v);
243✔
2191
      break;
243✔
2192
   case V_ASSIGN:
387✔
2193
      vlog_lower_continuous_assign(&g, v);
387✔
2194
      break;
387✔
2195
   case V_GATE_INST:
60✔
2196
      vlog_lower_gate_inst(&g, v);
60✔
2197
      break;
60✔
2198
   default:
×
2199
      CANNOT_HANDLE(v);
×
2200
   }
2201

2202
   vlog_lower_cleanup(&g);
837✔
2203
}
837✔
2204

2205
static void vlog_lower_net_decl(vlog_gen_t *g, vlog_node_t v, tree_t wrap,
556✔
2206
                                mir_value_t resfn)
2207
{
2208
   mir_type_t t_net_value = mir_int_type(g->mu, 0, 255);
556✔
2209
   mir_type_t t_net_signal = mir_signal_type(g->mu, t_net_value);
556✔
2210
   mir_type_t t_offset = mir_offset_type(g->mu);
556✔
2211

2212
   assert(wrap != NULL);
556✔
2213
   assert(!vlog_has_value(v));   // Should have been replaced with assign
556✔
2214

2215
   const type_info_t *ti = vlog_type_info(g, vlog_type(v));
556✔
2216
   const int total_size = ti->size * vlog_size(v);
556✔
2217

2218
   mir_value_t value = mir_const(g->mu, t_net_value, LOGIC_X);
556✔
2219
   mir_value_t count = mir_const(g->mu, t_offset, total_size);
556✔
2220
   mir_value_t size = mir_const(g->mu, t_offset, 1);
556✔
2221
   mir_value_t flags = mir_const(g->mu, t_offset, 0);
556✔
2222
   mir_value_t locus = mir_build_locus(g->mu, tree_to_object(wrap));
556✔
2223

2224
   mir_value_t signal = mir_build_init_signal(g->mu, t_net_value, count, size,
556✔
2225
                                              value, flags, locus,
2226
                                              MIR_NULL_VALUE);
556✔
2227

2228
   mir_build_resolve_signal(g->mu, signal, resfn);
556✔
2229

2230
   mir_value_t var = mir_add_var(g->mu, t_net_signal, MIR_NULL_STAMP,
556✔
2231
                                 vlog_ident(v), MIR_VAR_SIGNAL);
2232
   mir_build_store(g->mu, var, signal);
556✔
2233

2234
   mir_put_object(g->mu, v, var);
556✔
2235
}
556✔
2236

2237
static void vlog_lower_var_decl(vlog_gen_t *g, vlog_node_t v, tree_t wrap)
544✔
2238
{
2239
   const type_info_t *ti = vlog_type_info(g, vlog_type(v));
544✔
2240

2241
   if (mir_get_class(g->mu, ti->type) == MIR_TYPE_CONTEXT) {
544✔
2242
      // Class variable
2243
      mir_value_t null = mir_build_null(g->mu, ti->type);
6✔
2244
      mir_value_t var = mir_add_var(g->mu, ti->type, MIR_NULL_STAMP,
6✔
2245
                                    vlog_ident(v), 0);
2246
      mir_build_store(g->mu, var, null);
6✔
2247

2248
      mir_put_object(g->mu, v, var);
6✔
2249
      return;
6✔
2250
   }
2251

2252
   mir_type_t t_logic = mir_int_type(g->mu, 0, 3);
538✔
2253
   mir_type_t t_logic_signal = mir_signal_type(g->mu, t_logic);
538✔
2254
   mir_type_t t_offset = mir_offset_type(g->mu);
538✔
2255

2256
   const int total_size = ti->size * vlog_size(v);
538✔
2257

2258
   assert(wrap != NULL);
538✔
2259

2260
   mir_value_t value;
538✔
2261
   if (vlog_has_value(v)) {
538✔
2262
      mir_value_t tmp = MIR_NULL_VALUE;
54✔
2263
      if (ti->size > 1) {
54✔
2264
         mir_type_t t_elem = mir_logic_type(g->mu);
18✔
2265
         mir_type_t t_array = mir_carray_type(g->mu, total_size, t_elem);
18✔
2266
         tmp = vlog_get_temp(g, t_array);
18✔
2267
      }
2268

2269
      mir_value_t packed = vlog_lower_rvalue(g, vlog_value(v));
54✔
2270
      mir_value_t cast = mir_build_cast(g->mu, ti->type, packed);
54✔
2271
      value = mir_build_unpack(g->mu, cast, 0, tmp);
54✔
2272
   }
2273
   else
2274
      value = mir_const(g->mu, t_logic, LOGIC_X);
484✔
2275

2276
   mir_value_t count = mir_const(g->mu, t_offset, total_size);
538✔
2277
   mir_value_t size = mir_const(g->mu, t_offset, 1);
538✔
2278
   mir_value_t flags = mir_const(g->mu, t_offset, 0);
538✔
2279
   mir_value_t locus = mir_build_locus(g->mu, tree_to_object(wrap));
538✔
2280

2281
   mir_value_t signal = mir_build_init_signal(g->mu, t_logic, count, size,
538✔
2282
                                              value, flags, locus,
2283
                                              MIR_NULL_VALUE);
538✔
2284

2285
   mir_value_t var = mir_add_var(g->mu, t_logic_signal, MIR_NULL_STAMP,
538✔
2286
                                 vlog_ident(v), MIR_VAR_SIGNAL);
2287
   mir_build_store(g->mu, var, signal);
538✔
2288

2289
   mir_put_object(g->mu, v, var);
538✔
2290
}
2291

2292
static void vlog_lower_genvar_decl(vlog_gen_t *g, vlog_node_t v)
9✔
2293
{
2294
   const type_info_t *ti = vlog_type_info(g, vlog_type(v));
9✔
2295

2296
   mir_value_t var = mir_add_var(g->mu, ti->type, MIR_NULL_STAMP,
9✔
2297
                                 vlog_ident(v), 0);
2298
   mir_build_store(g->mu, var, mir_const_vec(g->mu, ti->type, ~0, ~0));
9✔
2299

2300
   mir_put_object(g->mu, v, var);
9✔
2301
}
9✔
2302

2303
static void vlog_lower_locals(vlog_gen_t *g, vlog_node_t v)
27✔
2304
{
2305
   const int ndecls = vlog_decls(v);
27✔
2306
   for (int i = 0; i < ndecls; i++) {
39✔
2307
      vlog_node_t d = vlog_decl(v, i);
12✔
2308
      switch (vlog_kind(d)) {
12✔
2309
      case V_VAR_DECL:
12✔
2310
         {
2311
            const type_info_t *ti = vlog_type_info(g, vlog_type(d));
12✔
2312
            mir_value_t var = mir_add_var(g->mu, ti->type, ti->stamp,
12✔
2313
                                          vlog_ident(d), 0);
2314
            mir_put_object(g->mu, d, var);
12✔
2315

2316
            mir_value_t init;
12✔
2317
            if (vlog_has_value(d))
12✔
2318
               init = vlog_lower_rvalue(g, vlog_value(d));
×
2319
            else
2320
               init = vlog_lower_default_value(g, ti);
12✔
2321

2322
            mir_build_store(g->mu, var, init);
12✔
2323
         }
2324
         break;
12✔
2325
      default:
×
2326
         CANNOT_HANDLE(d);
12✔
2327
      }
2328
   }
2329
}
27✔
2330

2331
static void vlog_lower_func_decl(mir_unit_t *mu, object_t *obj)
24✔
2332
{
2333
   vlog_node_t v = vlog_from_object(obj);
24✔
2334
   assert(vlog_kind(v) == V_FUNC_DECL);
24✔
2335

2336
   vlog_gen_t g = {
24✔
2337
      .mu = mu,
2338
   };
2339

2340
   const type_info_t *ti = vlog_type_info(&g, vlog_type(v));
24✔
2341
   mir_set_result(mu, ti->type);
24✔
2342

2343
   mir_type_t t_context = mir_context_type(mu, mir_get_parent(mu));
24✔
2344
   mir_add_param(mu, t_context, MIR_NULL_STAMP, ident_new("context"));
24✔
2345

2346
   const int nports = vlog_ports(v);
24✔
2347
   for (int i = 0; i < nports; i++) {
60✔
2348
      vlog_node_t port = vlog_port(v, i);
36✔
2349
      const type_info_t *pti = vlog_type_info(&g, vlog_type(port));
36✔
2350
      mir_value_t value = mir_add_param(mu, pti->type, pti->stamp,
36✔
2351
                                        vlog_ident(port));
2352
      mir_put_object(mu, port, value);
36✔
2353
   }
2354

2355
   mir_value_t result = mir_add_var(mu, ti->type, ti->stamp, vlog_ident(v), 0);
24✔
2356
   mir_put_object(mu, v, result);
24✔
2357

2358
   mir_build_store(mu, result, vlog_lower_default_value(&g, ti));
24✔
2359

2360
   vlog_lower_locals(&g, v);
24✔
2361
   vlog_lower_stmts(&g, v);
24✔
2362

2363
   if (!mir_block_finished(mu, MIR_NULL_BLOCK))
24✔
2364
      mir_build_return(mu, mir_build_load(mu, result));
24✔
2365
}
24✔
2366

2367
static void vlog_lower_class_decl(mir_unit_t *mu, object_t *obj)
3✔
2368
{
2369
   vlog_node_t v = vlog_from_object(obj);
3✔
2370
   assert(vlog_kind(v) == V_CLASS_DECL);
3✔
2371

2372
   vlog_gen_t g = {
3✔
2373
      .mu = mu,
2374
   };
2375

2376
   mir_type_t t_context = mir_context_type(mu, mir_get_parent(mu));
3✔
2377
   mir_add_param(mu, t_context, MIR_NULL_STAMP, ident_new("context"));
3✔
2378

2379
   vlog_lower_locals(&g, v);
3✔
2380

2381
   if (!mir_block_finished(mu, MIR_NULL_BLOCK))
3✔
2382
      mir_build_return(mu, MIR_NULL_VALUE);
3✔
2383
}
3✔
2384

2385
static mir_type_t vlog_lower_vhdl_type(mir_unit_t *mu, type_t type)
168✔
2386
{
2387
   if (type_eq(type, ieee_type(IEEE_STD_ULOGIC)))
168✔
2388
      return mir_int_type(mu, 0, 8);
36✔
2389
   else if (type_eq(type, ieee_type(IEEE_STD_ULOGIC_VECTOR)))
132✔
2390
      return mir_uarray_type(mu, 1, mir_int_type(mu, 0, 8));
18✔
2391
   else if (type_eq(type, verilog_type(VERILOG_NET_VALUE)))
114✔
2392
      return mir_int_type(mu, 0, 255);
87✔
2393
   else if (type_eq(type, verilog_type(VERILOG_LOGIC)))
27✔
2394
      return mir_int_type(mu, 0, 3);
×
2395
   else if (type_eq(type, verilog_type(VERILOG_WIRE_ARRAY))
27✔
2396
            || type_eq(type, verilog_type(VERILOG_NET_ARRAY)))
27✔
2397
      return mir_uarray_type(mu, 1, mir_int_type(mu, 0, 3));
27✔
2398

2399
   fatal_trace("cannot lower VHDL type %s", type_pp(type));
2400
}
2401

2402
static void vlog_lower_converter(mir_unit_t *mu, tree_t cf, mir_value_t in,
168✔
2403
                                 mir_value_t out)
2404
{
2405
   tree_t decl = tree_ref(cf);
168✔
2406
   assert(tree_kind(decl) == T_FUNC_DECL);
168✔
2407

2408
   type_t rtype = type_result(tree_type(decl));
168✔
2409

2410
   // Dummy return value to force function calling convention
2411
   mir_type_t t_offset = mir_offset_type(mu);
168✔
2412
   mir_set_result(mu, t_offset);
168✔
2413

2414
   mir_type_t t_context = mir_context_type(mu, mir_get_parent(mu));
168✔
2415
   mir_add_param(mu, t_context, MIR_NULL_STAMP, ident_new("context"));
168✔
2416

2417
   mir_type_t t_conv = mir_conversion_type(mu);
168✔
2418
   mir_value_t conv =
168✔
2419
      mir_add_param(mu, t_conv, MIR_NULL_STAMP, ident_new("cf"));
168✔
2420

2421
   mir_type_t t_out = vlog_lower_vhdl_type(mu, rtype);
168✔
2422

2423
   ident_t func = tree_ident2(tree_ref(cf));
168✔
2424

2425
   mir_value_t pkg = mir_build_link_package(mu, well_known(W_NVC_VERILOG));
168✔
2426

2427
   mir_value_t count = MIR_NULL_VALUE;
168✔
2428
   if (mir_is(mu, in, MIR_TYPE_UARRAY)) {
168✔
2429
      count = mir_build_uarray_len(mu, in, 0);
24✔
2430
      in = mir_build_unwrap(mu, in);
24✔
2431
   }
2432
   else if (type_is_array(rtype)) {
144✔
2433
      int64_t length;
21✔
2434
      if (!folded_length(range_of(tree_type(tree_value(cf)), 0), &length))
21✔
2435
         should_not_reach_here();
2436

2437
      count = mir_const(mu, t_offset, length);
21✔
2438
   }
2439

2440
   mir_value_t resolved = mir_build_resolved(mu, in);
168✔
2441

2442
   mir_value_t arg;
168✔
2443
   if (!mir_is_null(count)) {
168✔
2444
      mir_dim_t dims[] = {
45✔
2445
         { .left  = mir_const(mu, t_offset, 1),
45✔
2446
           .right = count,
2447
           .dir   = mir_const(mu, mir_bool_type(mu), RANGE_TO),
45✔
2448
         }
2449
      };
2450
      arg = mir_build_wrap(mu, resolved, dims, 1);
45✔
2451
   }
2452
   else {
2453
      arg = mir_build_load(mu, resolved);
123✔
2454
      count = mir_const(mu, t_offset, 1);
123✔
2455
   }
2456

2457
   mir_value_t args[] = { pkg, arg };
168✔
2458

2459
   mir_value_t result = mir_build_fcall(mu, func, t_out, MIR_NULL_STAMP,
168✔
2460
                                        args, ARRAY_LEN(args));
2461

2462
   if (mir_is(mu, result, MIR_TYPE_UARRAY))
168✔
2463
      result = mir_build_unwrap(mu, result);
45✔
2464

2465
   if (mir_is(mu, out, MIR_TYPE_UARRAY))
168✔
2466
      out = mir_build_unwrap(mu, out);
9✔
2467

2468
   mir_build_put_conversion(mu, conv, out, count, result);
168✔
2469

2470
   mir_build_return(mu, mir_const(mu, t_offset, 0));
168✔
2471
}
168✔
2472

2473
static void vlog_lower_convert_in(mir_unit_t *mu, object_t *obj)
114✔
2474
{
2475
   tree_t map = tree_from_object(obj);
114✔
2476
   assert(tree_kind(map) == T_PARAM);
114✔
2477

2478
   tree_t cf = tree_value(map);
114✔
2479
   assert(tree_kind(cf) == T_CONV_FUNC);
114✔
2480

2481
   mir_context_t *mc = mir_get_context(mu);
114✔
2482

2483
   ident_t parent1 = mir_get_parent(mu);
114✔
2484
   mir_shape_t *shape1 = mir_get_shape(mc, parent1);
114✔
2485

2486
   ident_t parent2 = mir_get_shape_parent(shape1);
114✔
2487
   mir_shape_t *shape2 = mir_get_shape(mc, parent2);
114✔
2488

2489
   tree_t arg = tree_value(cf);
114✔
2490
   assert(tree_kind(arg) == T_REF);
114✔
2491

2492
   int nth = mir_find_slot(shape2, tree_ident(tree_ref(arg)));
114✔
2493
   assert(nth >= 0);
114✔
2494

2495
   mir_value_t in_upref = mir_build_var_upref(mu, 2, nth);
114✔
2496
   mir_value_t in_nets = mir_build_load(mu, in_upref);
114✔
2497

2498
   int hops;
114✔
2499
   mir_value_t var = mir_search_object(mu, map, &hops);
114✔
2500
   assert(!mir_is_null(var));
114✔
2501
   assert(hops == 1);
114✔
2502

2503
   mir_value_t out_upref = mir_build_var_upref(mu, hops, var.id);
114✔
2504
   mir_value_t out_nets = mir_build_load(mu, out_upref);
114✔
2505

2506
   vlog_lower_converter(mu, cf, in_nets, out_nets);
114✔
2507
}
114✔
2508

2509
static void vlog_lower_convert_out(mir_unit_t *mu, object_t *obj)
54✔
2510
{
2511
   tree_t map = tree_from_object(obj);
54✔
2512
   assert(tree_kind(map) == T_PARAM);
54✔
2513

2514
   tree_t cf = tree_name(map);
54✔
2515
   assert(tree_kind(cf) == T_CONV_FUNC);
54✔
2516

2517
   mir_context_t *mc = mir_get_context(mu);
54✔
2518

2519
   ident_t parent1 = mir_get_parent(mu);
54✔
2520
   mir_shape_t *shape1 = mir_get_shape(mc, parent1);
54✔
2521

2522
   ident_t parent2 = mir_get_shape_parent(shape1);
54✔
2523
   mir_shape_t *shape2 = mir_get_shape(mc, parent2);
54✔
2524

2525
   int hops;
54✔
2526
   mir_value_t var = mir_search_object(mu, map, &hops);
54✔
2527
   assert(!mir_is_null(var));
54✔
2528
   assert(hops == 1);
54✔
2529

2530
   mir_value_t in_upref = mir_build_var_upref(mu, hops, var.id);
54✔
2531
   mir_value_t in_nets = mir_build_load(mu, in_upref);
54✔
2532

2533
   tree_t dst = tree_value(map);
54✔
2534
   assert(tree_kind(dst) == T_REF);
54✔
2535

2536
   int nth = mir_find_slot(shape2, tree_ident(tree_ref(dst)));
54✔
2537
   assert(nth >= 0);
54✔
2538

2539
   mir_value_t out_upref = mir_build_var_upref(mu, 2, nth);
54✔
2540
   mir_value_t out_nets = mir_build_load(mu, out_upref);
54✔
2541

2542
   vlog_lower_converter(mu, cf, in_nets, out_nets);
54✔
2543
}
54✔
2544

2545
void vlog_lower_block(mir_context_t *mc, ident_t parent, tree_t b)
437✔
2546
{
2547
   tree_t hier = tree_decl(b, 0);
437✔
2548
   assert(tree_kind(hier) == T_HIER);
437✔
2549

2550
   mir_shape_t *shape = mir_get_shape(mc, parent);
437✔
2551
   ident_t qual = tree_ident2(hier);
437✔
2552
   mir_unit_t *mu = mir_unit_new(mc, qual, tree_to_object(b),
437✔
2553
                                 MIR_UNIT_INSTANCE, shape);
2554

2555
   tree_t wrap = tree_ref(hier);
437✔
2556
   assert(tree_kind(wrap) == T_VERILOG);
437✔
2557

2558
   vlog_node_t body = tree_vlog(wrap);
437✔
2559
   const vlog_kind_t body_kind = vlog_kind(body);
437✔
2560
   assert(body_kind == V_INST_BODY || body_kind == V_BLOCK);
437✔
2561

2562
   hash_t *map = hash_new(16);
437✔
2563

2564
   const int vhdl_ndecls = tree_decls(b);
437✔
2565
   const int vlog_ndecls = vlog_decls(body);
437✔
2566

2567
   for (int i = 1, pos = 0; i < vhdl_ndecls; i++) {
1,713✔
2568
      tree_t t = tree_decl(b, i);
1,276✔
2569
      ident_t id = tree_ident(t);
1,276✔
2570
      for (; pos < vlog_ndecls; pos++) {
3,783✔
2571
         vlog_node_t v = vlog_decl(body, pos);
2,507✔
2572
         if (vlog_kind(v) == V_PORT_DECL)
2,507✔
2573
            continue;
341✔
2574
         else if (vlog_ident(v) == id) {
2,166✔
2575
            hash_put(map, v, t);
1,276✔
2576
            break;
1,276✔
2577
         }
2578
      }
2579

2580
      if (pos == vlog_ndecls)
1,276✔
2581
         fatal_trace("missing VHDL signal for %s", istr(id));
2582
   }
2583

2584
   const int vhdl_nports = tree_ports(b);
437✔
2585
   const int vlog_nports = body_kind == V_INST_BODY ? vlog_ports(body) : 0;
437✔
2586

2587
   for (int i = 0; i < vhdl_nports; i++)
626✔
2588
      hash_put(map, vlog_ref(vlog_ref(vlog_port(body, i))), tree_port(b, i));
189✔
2589

2590
   ident_t pkg_name = well_known(W_NVC_VERILOG);
437✔
2591
   mir_value_t pkg = mir_build_package_init(mu, pkg_name, MIR_NULL_VALUE);
437✔
2592

2593
   mir_type_t t_net_value = mir_int_type(mu, 0, 255);
437✔
2594
   mir_type_t t_resolution = mir_resolution_type(mu, t_net_value);
437✔
2595

2596
   ident_t var_name = ident_new("NVC.VERILOG.T_WIRE$resolution");
437✔
2597
   mir_value_t resfn = mir_build_link_var(mu, pkg, var_name, t_resolution);
437✔
2598

2599
   vlog_gen_t g = {
437✔
2600
      .mu = mu,
2601
   };
2602

2603
   for (int i = 0; i < vlog_ndecls; i++) {
2,075✔
2604
      vlog_node_t d = vlog_decl(body, i);
1,638✔
2605

2606
      switch (vlog_kind(d)) {
1,638✔
2607
      case V_PORT_DECL:
2608
         break;   // Translated below
2609
      case V_NET_DECL:
556✔
2610
         vlog_lower_net_decl(&g, d, hash_get(map, d), resfn);
556✔
2611
         break;
556✔
2612
      case V_VAR_DECL:
544✔
2613
         vlog_lower_var_decl(&g, d, hash_get(map, d));
544✔
2614
         break;
544✔
2615
      case V_GENVAR_DECL:
9✔
2616
         vlog_lower_genvar_decl(&g, d);
9✔
2617
         break;
9✔
2618
      case V_LOCALPARAM:
2619
         break;  // Always inlined for now
2620
      case V_FUNC_DECL:
27✔
2621
         mir_defer(mc, ident_prefix(vlog_ident2(d), vlog_ident(d), '.'), qual,
27✔
2622
                   MIR_UNIT_FUNCTION, vlog_lower_func_decl, vlog_to_object(d));
2623
         break;
27✔
2624
      case V_CLASS_DECL:
3✔
2625
         mir_defer(mc, ident_prefix(vlog_ident2(d), vlog_ident(d), '.'), qual,
3✔
2626
                   MIR_UNIT_PROTECTED, vlog_lower_class_decl,
2627
                   vlog_to_object(d));
2628
         break;
3✔
2629
      case V_TYPE_DECL:
2630
         break;
2631
      default:
×
2632
         CANNOT_HANDLE(d);
1,638✔
2633
      }
2634
   }
2635

2636
   mir_value_t self = mir_build_context_upref(mu, 0);
437✔
2637
   mir_type_t t_self = mir_context_type(mu, qual);
437✔
2638
   mir_type_t t_offset = mir_offset_type(mu);
437✔
2639

2640
   for (int i = 0; i < vlog_nports; i++) {
778✔
2641
      vlog_node_t ref = vlog_port(body, i);
341✔
2642
      assert(vlog_kind(ref) == V_REF);
341✔
2643

2644
      vlog_node_t port = vlog_ref(ref);
341✔
2645
      assert(vlog_kind(port) == V_PORT_DECL);
341✔
2646

2647
      int hops;
341✔
2648
      mir_value_t var = mir_search_object(mu, vlog_ref(port), &hops);
341✔
2649
      assert(!mir_is_null(var));
341✔
2650
      assert(hops == 0);
341✔
2651

2652
      mir_put_object(mu, port, var);
341✔
2653

2654
      if (i >= vhdl_nports)
341✔
2655
         continue;   // Port conversion only for mixed instantiation
152✔
2656

2657
      mir_value_t count = mir_const(mu, t_offset, vlog_size(vlog_type(port)));
189✔
2658

2659
      tree_t map = tree_param(b, i);
189✔
2660
      tree_t value = tree_value(map);
189✔
2661

2662
      mir_value_t in_conv = MIR_NULL_VALUE;
189✔
2663
      if (tree_kind(value) == T_CONV_FUNC) {
189✔
2664
         mir_put_object(mu, map, var);
120✔
2665

2666
         ident_t func = ident_sprintf("%s.%s$verilog_convert_in",
120✔
2667
                                      istr(qual), istr(vlog_ident(port)));
2668
         mir_defer(mc, func, qual, MIR_UNIT_FUNCTION, vlog_lower_convert_in,
120✔
2669
                      tree_to_object(map));
2670

2671
         mir_value_t closure =
120✔
2672
            mir_build_closure(mu, func, self, t_self, t_offset);
120✔
2673
         in_conv = mir_build_port_conversion(mu, closure, closure);
120✔
2674

2675
         value = tree_value(value);
120✔
2676
      }
2677

2678
      assert(tree_kind(value) == T_REF);
189✔
2679

2680
      tree_t vhdl_port = tree_ref(value);
189✔
2681
      assert(tree_kind(vhdl_port) == T_PORT_DECL);
189✔
2682

2683
      int nth = mir_find_slot(shape, tree_ident(vhdl_port));
189✔
2684
      assert(nth >= 0);
189✔
2685

2686
      mir_value_t upref = mir_build_var_upref(mu, 1, nth);
189✔
2687
      mir_value_t dst_nets = mir_build_load(mu, upref);
189✔
2688

2689
      type_t vhdl_type = tree_type(vhdl_port);
189✔
2690
      assert(dimension_of(vhdl_type) == 1);
189✔
2691

2692
      mir_value_t dst_count;
189✔
2693
      if (mir_is(mu, dst_nets, MIR_TYPE_UARRAY)) {
189✔
2694
         dst_count = mir_build_uarray_len(mu, dst_nets, 0);
35✔
2695
         dst_nets = mir_build_unwrap(mu, dst_nets);
35✔
2696
      }
2697
      else if (type_is_array(vhdl_type)) {
154✔
2698
         int64_t cval;
28✔
2699
         if (folded_length(range_of(vhdl_type, 0), &cval))
28✔
2700
            dst_count = mir_const(mu, t_offset, cval);
28✔
2701
         else
2702
            should_not_reach_here();
2703
      }
2704
      else if (type_is_scalar(vhdl_type))
126✔
2705
         dst_count = mir_const(mu, t_offset, 1);
126✔
2706
      else
2707
         should_not_reach_here();
2708

2709
      mir_value_t out_conv = MIR_NULL_VALUE;
189✔
2710
      if (tree_subkind(map) == P_NAMED) {
189✔
2711
         tree_t name = tree_name(map);
114✔
2712
         if (tree_kind(name) == T_CONV_FUNC) {
114✔
2713
            mir_put_object(mu, map, var);
69✔
2714

2715
            ident_t func = ident_sprintf("%s.%s$verilog_convert_out",
69✔
2716
                                         istr(qual), istr(vlog_ident(port)));
2717
            mir_defer(mc, func, qual, MIR_UNIT_FUNCTION, vlog_lower_convert_out,
69✔
2718
                      tree_to_object(map));
2719

2720
            mir_value_t closure =
69✔
2721
               mir_build_closure(mu, func, self, t_self, t_offset);
69✔
2722
            out_conv = mir_build_port_conversion(mu, closure, closure);
69✔
2723
         }
2724
      }
2725

2726
      mir_value_t src_nets = mir_build_load(mu, var);
189✔
2727
      mir_value_t src_count =
189✔
2728
         mir_const(mu, t_offset, vlog_size(vlog_type(port)));
189✔
2729

2730
      mir_value_t locus = mir_build_locus(mu, tree_to_object(map));
189✔
2731
      mir_build_length_check(mu, src_count, dst_count, locus, MIR_NULL_VALUE);
189✔
2732

2733
      switch (vlog_subkind(port)) {
189✔
2734
      case V_PORT_INPUT:
120✔
2735
         if (mir_is_null(in_conv))
120✔
2736
            mir_build_map_signal(mu, dst_nets, src_nets, count);
×
2737
         else {
2738
            mir_build_convert_out(mu, in_conv, src_nets, count);
120✔
2739
            mir_build_convert_in(mu, in_conv, dst_nets, count);
120✔
2740
         }
2741
         break;
2742
      case V_PORT_OUTPUT:
69✔
2743
         if (mir_is_null(out_conv))
69✔
2744
            mir_build_map_signal(mu, src_nets, dst_nets, count);
×
2745
         else {
2746
            mir_build_convert_out(mu, out_conv, dst_nets, count);
69✔
2747
            mir_build_convert_in(mu, out_conv, src_nets, count);
69✔
2748
         }
2749
         break;
2750
      default:
×
2751
         CANNOT_HANDLE(port);
189✔
2752
      }
2753
   }
2754

2755
   mir_build_return(mu, MIR_NULL_VALUE);
437✔
2756

2757
   vlog_lower_cleanup(&g);
437✔
2758

2759
   hash_free(map);
437✔
2760

2761
   mir_optimise(mu, MIR_PASS_O1);
437✔
2762
   mir_put_unit(mc, mu);
437✔
2763
}
437✔
2764

2765
mir_unit_t *vlog_lower_thunk(mir_context_t *mc, ident_t parent, vlog_node_t v)
27✔
2766
{
2767
   mir_unit_t *mu = mir_unit_new(mc, NULL, vlog_to_object(v), MIR_UNIT_THUNK,
27✔
2768
                                 mir_get_shape(mc, parent));
2769

2770
   vlog_gen_t g = {
27✔
2771
      .mu = mu,
2772
   };
2773

2774
   switch (vlog_kind(v)) {
27✔
2775
   case V_FOR_INIT:
9✔
2776
      assert(vlog_decls(v) == 0);   // TODO
9✔
2777
      // Fall-through
2778
   case V_FOR_STEP:
2779
      vlog_lower_stmts(&g, v);
18✔
2780
      mir_build_return(mu, MIR_NULL_VALUE);
18✔
2781
      break;
18✔
2782
   default:
9✔
2783
      {
2784
         mir_value_t value = vlog_lower_rvalue(&g, v);
9✔
2785
         mir_set_result(mu, mir_get_type(mu, value));
9✔
2786
         mir_build_return(mu, value);
9✔
2787
      }
2788
   }
2789

2790
   vlog_lower_cleanup(&g);
27✔
2791
   return mu;
27✔
2792
}
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