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

nickg / nvc / 13738584171

08 Mar 2025 12:57PM UTC coverage: 92.236% (-0.05%) from 92.281%
13738584171

push

github

nickg
Add a simple pointer provenance tracking scheme

52 of 53 new or added lines in 3 files covered. (98.11%)

230 existing lines in 7 files now uncovered.

68028 of 73754 relevant lines covered (92.24%)

433200.43 hits per line

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

97.98
/src/jit/jit-irgen.c
1
//
2
//  Copyright (C) 2022-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 "cov/cov-api.h"
20
#include "diag.h"
21
#include "jit/jit-ffi.h"
22
#include "jit/jit-ffi.h"
23
#include "jit/jit-priv.h"
24
#include "mask.h"
25
#include "mir/mir-node.h"
26
#include "mir/mir-unit.h"
27
#include "option.h"
28
#include "rt/rt.h"
29
#include "tree.h"
30

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

37
typedef struct _irgen_label irgen_label_t;
38
typedef struct _patch_list  patch_list_t;
39

40
#define PATCH_CHUNK_SZ  4
41
#define MAX_STACK_ALLOC 65536
42
#define DEDUP_PREFIX    16384
43

44
struct _patch_list {
45
   patch_list_t *next;
46
   unsigned      count;
47
   unsigned      offsets[PATCH_CHUNK_SZ];
48
};
49

50
struct _irgen_label {
51
   jit_label_t    label;
52
   unsigned       uses;
53
   patch_list_t   patchlist;
54
   irgen_label_t *next;
55
};
56

57
typedef struct {
58
   jit_func_t     *func;
59
   jit_value_t    *vars;
60
   jit_value_t    *params;
61
   jit_reg_t       next_reg;
62
   jit_value_t    *map;
63
   irgen_label_t  *labels;
64
   irgen_label_t **blocks;
65
   mir_unit_t     *mu;
66
   size_t          cpoolptr;
67
   size_t          oldptr;
68
   jit_value_t     statereg;
69
   jit_value_t     contextarg;
70
   mir_value_t     flags;
71
   mir_block_t     curblock;
72
   unsigned        bufsz;
73
   bool            used_tlab;
74
   bool            stateless;
75
   bool            needs_context;
76
} jit_irgen_t;
77

78
////////////////////////////////////////////////////////////////////////////////
79
// IR emission
80

81
static inline jit_value_t jit_value_from_reg(jit_reg_t reg)
1,455,813✔
82
{
83
   jit_value_t value = { .kind = JIT_VALUE_REG, .reg = reg };
1,455,813✔
84
   return value;
1,455,813✔
85
}
86

87
static inline jit_value_t jit_value_from_int64(int64_t immed)
3,047,067✔
88
{
89
   jit_value_t value = { .kind = JIT_VALUE_INT64, .int64 = immed };
3,047,067✔
90
   return value;
3,047,067✔
91
}
92

93
static inline jit_value_t jit_value_from_double(double immed)
21,100✔
94
{
95
   return (jit_value_t){ .kind = JIT_VALUE_DOUBLE, .dval = immed };
21,100✔
96
}
97

98
static inline jit_value_t jit_value_from_cpool_addr(int offset)
23,530✔
99
{
100
   jit_value_t value = { .kind = JIT_ADDR_CPOOL, .int64 = offset };
23,530✔
101
   return value;
23,530✔
102
}
103

104
static inline jit_value_t jit_value_from_loc(const loc_t *loc)
1,132,526✔
105
{
106
   jit_value_t value = { .kind = JIT_VALUE_LOC, .loc = *loc };
1,132,526✔
107
   return value;
1,132,526✔
108
}
109

110
static inline jit_value_t jit_null_ptr(void)
25,547✔
111
{
112
   jit_value_t value = { .kind = JIT_ADDR_ABS, .int64 = 0 };
25,547✔
113
   return value;
25,547✔
114
}
115

116
static inline jit_reg_t jit_value_as_reg(jit_value_t value)
221,438✔
117
{
118
   assert(value.kind == JIT_VALUE_REG);
221,438✔
119
   return value.reg;
221,438✔
120
}
121

122
static inline bool jit_value_is_addr(jit_value_t value)
393,113✔
123
{
124
   switch (value.kind) {
393,113✔
125
   case JIT_ADDR_ABS:
126
   case JIT_ADDR_CPOOL:
127
   case JIT_ADDR_REG:
128
      return true;
129
   default:
335,910✔
130
      return false;
335,910✔
131
   }
132
}
133

134
static jit_value_t jit_addr_from_value(jit_value_t value, int32_t disp)
592,538✔
135
{
136
   switch (value.kind) {
592,538✔
137
   case JIT_VALUE_REG:
272,965✔
138
      return (jit_value_t){
272,965✔
139
         .kind = JIT_ADDR_REG,
140
         .disp = disp,
141
         .reg = value.reg
272,965✔
142
      };
143
   case JIT_VALUE_INT64:
3,024✔
144
   case JIT_ADDR_ABS:
145
      return (jit_value_t){
3,024✔
146
         .kind = JIT_ADDR_ABS,
147
         .int64 = value.int64 + disp
3,024✔
148
      };
149
   case JIT_ADDR_CPOOL:
7,103✔
150
      return (jit_value_t){
7,103✔
151
         .kind = value.kind,
152
         .int64 = value.int64 + disp
7,103✔
153
      };
154
   case JIT_ADDR_REG:
309,446✔
155
      return (jit_value_t){
309,446✔
156
         .kind = JIT_ADDR_REG,
157
         .disp = value.disp + disp,
309,446✔
158
         .reg = value.reg
309,446✔
159
      };
UNCOV
160
   default:
×
161
      fatal_trace("cannot convert value kind %d to address", value.kind);
162
   }
163
}
164

165
static jit_value_t jit_addr_from_cover_tag(uint32_t tag)
2,296✔
166
{
167
   return (jit_value_t){
2,296✔
168
      .kind = JIT_ADDR_COVER,
169
      .int64 = tag,
170
   };
171
}
172

173
static jit_value_t jit_value_from_label(irgen_label_t *l)
178,708✔
174
{
175
   return (jit_value_t){ .kind = JIT_VALUE_LABEL, .label = l->label };
178,708✔
176
}
177

178
static jit_value_t jit_value_from_handle(jit_handle_t handle)
91,034✔
179
{
180
   return (jit_value_t){ .kind = JIT_VALUE_HANDLE, .handle = handle };
91,034✔
181
}
182

183
static jit_value_t jit_value_from_exit(jit_exit_t exit)
123,163✔
184
{
185
   return (jit_value_t){ .kind = JIT_VALUE_EXIT, .exit = exit };
123,163✔
186
}
187

188
static jit_ir_t *irgen_append(jit_irgen_t *g)
3,674,057✔
189
{
190
   if (g->func->nirs == g->bufsz) {
3,674,057✔
191
      g->bufsz = MAX(g->bufsz * 2, 1024);
43,162✔
192
      g->func->irbuf = xrealloc_array(g->func->irbuf, g->bufsz,
43,162✔
193
                                      sizeof(jit_ir_t));
194
   }
195

196
   return &(g->func->irbuf[g->func->nirs++]);
3,674,057✔
197
}
198

199
static jit_reg_t irgen_alloc_reg(jit_irgen_t *g)
1,205,834✔
200
{
201
   if (unlikely(g->next_reg == JIT_REG_INVALID))
1,205,834✔
UNCOV
202
      fatal("unit %s is too big to compile", istr(g->func->name));
×
203
   else
204
      return g->next_reg++;
1,205,834✔
205
}
206

207
static irgen_label_t *irgen_alloc_label(jit_irgen_t *g)
213,384✔
208
{
209
   irgen_label_t *l = xcalloc(sizeof(irgen_label_t));
213,384✔
210
   l->next  = g->labels;
213,384✔
211
   l->label = JIT_LABEL_INVALID;
213,384✔
212

213
   return (g->labels = l);
213,384✔
214
}
215

216
static void irgen_bind_label(jit_irgen_t *g, irgen_label_t *l)
213,384✔
217
{
218
   assert(l->label == JIT_LABEL_INVALID);
213,384✔
219

220
   l->label = g->func->nirs;
213,384✔
221

222
   for (patch_list_t *p = &(l->patchlist); p; p = p->next) {
426,815✔
223
      for (int i = 0; i < p->count; i++) {
368,223✔
224
         jit_ir_t *ir = &(g->func->irbuf[p->offsets[i]]);
154,792✔
225
         if (ir->arg1.kind == JIT_VALUE_LABEL)
154,792✔
226
            ir->arg1.label = l->label;
136,639✔
227
         else if (ir->arg2.kind == JIT_VALUE_LABEL)
18,153✔
228
            ir->arg2.label = l->label;
18,153✔
229
         else
230
            fatal_trace("cannot find label argument to patch");
231
      }
232
   }
233

234
   for (patch_list_t *p = l->patchlist.next, *tmp; p; p = tmp) {
213,431✔
235
      tmp = p->next;
47✔
236
      free(p);
47✔
237
   }
238
}
213,384✔
239

240
static jit_cc_t irgen_get_jit_cc(mir_cmp_t cmp)
33,541✔
241
{
242
   switch (cmp) {
33,541✔
243
   case MIR_CMP_EQ: return JIT_CC_EQ;
244
   case MIR_CMP_NEQ: return JIT_CC_NE;
245
   case MIR_CMP_LT: return JIT_CC_LT;
246
   case MIR_CMP_GT: return JIT_CC_GT;
247
   case MIR_CMP_LEQ: return JIT_CC_LE;
248
   case MIR_CMP_GEQ: return JIT_CC_GE;
249
   default: return JIT_CC_NONE;
250
   }
251
}
252

253
static void irgen_emit_nullary(jit_irgen_t *g, jit_op_t op, jit_cc_t cc,
139,512✔
254
                               jit_reg_t result)
255
{
256
   jit_ir_t *ir = irgen_append(g);
139,512✔
257
   ir->op        = op;
139,512✔
258
   ir->size      = JIT_SZ_UNSPEC;
139,512✔
259
   ir->cc        = cc;
139,512✔
260
   ir->target    = 0;
139,512✔
261
   ir->result    = result;
139,512✔
262
   ir->arg1.kind = JIT_VALUE_INVALID;
139,512✔
263
   ir->arg2.kind = JIT_VALUE_INVALID;
139,512✔
264
}
139,512✔
265

266
static jit_ir_t *irgen_emit_unary(jit_irgen_t *g, jit_op_t op, jit_size_t sz,
1,055,095✔
267
                                  jit_cc_t cc, jit_reg_t result,
268
                                  jit_value_t arg)
269
{
270
   jit_ir_t *ir = irgen_append(g);
1,055,095✔
271
   ir->op        = op;
1,055,095✔
272
   ir->size      = sz;
1,055,095✔
273
   ir->cc        = cc;
1,055,095✔
274
   ir->target    = 0;
1,055,095✔
275
   ir->result    = result;
1,055,095✔
276
   ir->arg1      = arg;
1,055,095✔
277
   ir->arg2.kind = JIT_VALUE_INVALID;
1,055,095✔
278

279
   return ir;
1,055,095✔
280
}
281

282
static jit_ir_t *irgen_emit_binary(jit_irgen_t *g, jit_op_t op, jit_size_t sz,
2,479,450✔
283
                                   jit_cc_t cc, jit_reg_t result,
284
                                   jit_value_t arg1, jit_value_t arg2)
285
{
286
   jit_ir_t *ir = irgen_append(g);
2,479,450✔
287
   ir->op     = op;
2,479,450✔
288
   ir->size   = sz;
2,479,450✔
289
   ir->cc     = cc;
2,479,450✔
290
   ir->target = 0;
2,479,450✔
291
   ir->size   = sz;
2,479,450✔
292
   ir->result = result;
2,479,450✔
293
   ir->arg1   = arg1;
2,479,450✔
294
   ir->arg2   = arg2;
2,479,450✔
295

296
   return ir;
2,479,450✔
297
}
298

299
static void irgen_patch_label(jit_irgen_t *g, jit_ir_t *ir, irgen_label_t *l)
178,708✔
300
{
301
   if (l->label == JIT_LABEL_INVALID) {
178,708✔
302
      patch_list_t *p = &(l->patchlist);
154,792✔
303
      for (; p->count == PATCH_CHUNK_SZ; p = p->next) {
155,181✔
304
         if (p->next == NULL)
389✔
305
            p->next = xcalloc(sizeof(patch_list_t));
47✔
306
      }
307
      p->offsets[p->count++] = ir - g->func->irbuf;
154,792✔
308
   }
309

310
   l->uses++;
178,708✔
311
}
178,708✔
312

313
static jit_value_t j_recv(jit_irgen_t *g, int pos)
187,753✔
314
{
315
   assert(pos < JIT_MAX_ARGS);
187,753✔
316
   jit_reg_t r = irgen_alloc_reg(g);
187,753✔
317
   irgen_emit_unary(g, J_RECV, JIT_SZ_UNSPEC, JIT_CC_NONE, r,
187,753✔
318
                    jit_value_from_int64(pos));
319
   return jit_value_from_reg(r);
187,753✔
320
}
321

322
static void j_send(jit_irgen_t *g, int pos, jit_value_t value)
852,364✔
323
{
324
   assert(pos < JIT_MAX_ARGS);
852,364✔
325
   irgen_emit_binary(g, J_SEND, JIT_SZ_UNSPEC, JIT_CC_NONE, JIT_REG_INVALID,
852,364✔
326
                     jit_value_from_int64(pos), value);
327
}
852,364✔
328

329
static void j_ret(jit_irgen_t *g)
68,079✔
330
{
331
   irgen_emit_nullary(g, J_RET, JIT_CC_NONE, JIT_REG_INVALID);
68,079✔
332
   g->flags = MIR_NULL_VALUE;
68,079✔
333
}
68,079✔
334

335
__attribute__((unused))
336
static void j_trap(jit_irgen_t *g)
13,414✔
337
{
338
   irgen_emit_nullary(g, J_TRAP, JIT_CC_NONE, JIT_REG_INVALID);
13,414✔
339
}
13,414✔
340

341
static void j_jump(jit_irgen_t *g, jit_cc_t cc, irgen_label_t *l)
160,555✔
342
{
343
   jit_ir_t *ir = irgen_emit_unary(g, J_JUMP, JIT_SZ_UNSPEC, cc,
160,555✔
344
                                   JIT_REG_INVALID, jit_value_from_label(l));
345
   irgen_patch_label(g, ir, l);
160,555✔
346
}
160,555✔
347

348
static void j_call(jit_irgen_t *g, jit_handle_t handle)
55,305✔
349
{
350
   irgen_emit_unary(g, J_CALL, JIT_SZ_UNSPEC, JIT_CC_NONE,
55,305✔
351
                    JIT_REG_INVALID, jit_value_from_handle(handle));
352
   g->flags = MIR_NULL_VALUE;
55,305✔
353
}
55,305✔
354

355
static jit_value_t j_neg(jit_irgen_t *g, jit_value_t arg)
31,524✔
356
{
357
   jit_reg_t r = irgen_alloc_reg(g);
31,524✔
358
   irgen_emit_unary(g, J_NEG, JIT_SZ_UNSPEC, JIT_CC_NONE, r, arg);
31,524✔
359
   return jit_value_from_reg(r);
31,524✔
360
}
361

362
static jit_value_t j_fneg(jit_irgen_t *g, jit_value_t arg)
6,144✔
363
{
364
   jit_reg_t r = irgen_alloc_reg(g);
6,144✔
365
   irgen_emit_unary(g, J_FNEG, JIT_SZ_UNSPEC, JIT_CC_NONE, r, arg);
6,144✔
366
   return jit_value_from_reg(r);
6,144✔
367
}
368

369
static jit_value_t j_rem(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
245✔
370
{
371
   jit_reg_t r = irgen_alloc_reg(g);
245✔
372
   irgen_emit_binary(g, J_REM, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
245✔
373
   return jit_value_from_reg(r);
245✔
374
}
375

376
static jit_value_t j_not(jit_irgen_t *g, jit_value_t arg)
2,834✔
377
{
378
   jit_reg_t r = irgen_alloc_reg(g);
2,834✔
379
   irgen_emit_unary(g, J_NOT, JIT_SZ_UNSPEC, JIT_CC_NONE, r, arg);
2,834✔
380
   return jit_value_from_reg(r);
2,834✔
381
}
382

383
static jit_value_t j_and(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
5,296✔
384
{
385
   jit_reg_t r = irgen_alloc_reg(g);
5,296✔
386
   irgen_emit_binary(g, J_AND, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
5,296✔
387
   return jit_value_from_reg(r);
5,296✔
388
}
389

390
static jit_value_t j_or(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
1,850✔
391
{
392
   jit_reg_t r = irgen_alloc_reg(g);
1,850✔
393
   irgen_emit_binary(g, J_OR, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
1,850✔
394
   return jit_value_from_reg(r);
1,850✔
395
}
396

397
static jit_value_t j_xor(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
50,236✔
398
{
399
   jit_reg_t r = irgen_alloc_reg(g);
50,236✔
400
   irgen_emit_binary(g, J_XOR, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
50,236✔
401
   return jit_value_from_reg(r);
50,236✔
402
}
403

404
static jit_value_t j_asr(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
21,079✔
405
{
406
   jit_reg_t r = irgen_alloc_reg(g);
21,079✔
407
   irgen_emit_binary(g, J_ASR, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
21,079✔
408
   return jit_value_from_reg(r);
21,079✔
409
}
410

411
static jit_value_t j_add(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
115,534✔
412
{
413
   jit_reg_t r = irgen_alloc_reg(g);
115,534✔
414
   irgen_emit_binary(g, J_ADD, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
115,534✔
415
   return jit_value_from_reg(r);
115,534✔
416
}
417

418
static jit_value_t j_adds(jit_irgen_t *g, jit_size_t sz, jit_cc_t cc,
1,913✔
419
                          jit_value_t lhs, jit_value_t rhs)
420
{
421
   jit_reg_t r = irgen_alloc_reg(g);
1,913✔
422
   irgen_emit_binary(g, J_ADD, sz, cc, r, lhs, rhs);
1,913✔
423
   g->flags = MIR_NULL_VALUE;
1,913✔
424
   return jit_value_from_reg(r);
1,913✔
425
}
426

427
static jit_value_t j_fadd(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
266✔
428
{
429
   jit_reg_t r = irgen_alloc_reg(g);
266✔
430
   irgen_emit_binary(g, J_FADD, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
266✔
431
   return jit_value_from_reg(r);
266✔
432
}
433

434
static jit_value_t j_mul(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
60,757✔
435
{
436
   jit_reg_t r = irgen_alloc_reg(g);
60,757✔
437
   irgen_emit_binary(g, J_MUL, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
60,757✔
438
   return jit_value_from_reg(r);
60,757✔
439
}
440

441
static jit_value_t j_muls(jit_irgen_t *g, jit_size_t sz, jit_cc_t cc,
325✔
442
                          jit_value_t lhs, jit_value_t rhs)
443
{
444
   jit_reg_t r = irgen_alloc_reg(g);
325✔
445
   irgen_emit_binary(g, J_MUL, sz, cc, r, lhs, rhs);
325✔
446
   g->flags = MIR_NULL_VALUE;
325✔
447
   return jit_value_from_reg(r);
325✔
448
}
449

450
static jit_value_t j_fmul(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
548✔
451
{
452
   jit_reg_t r = irgen_alloc_reg(g);
548✔
453
   irgen_emit_binary(g, J_FMUL, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
548✔
454
   return jit_value_from_reg(r);
548✔
455
}
456

457
static jit_value_t j_div(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
669✔
458
{
459
   jit_reg_t r = irgen_alloc_reg(g);
669✔
460
   irgen_emit_binary(g, J_DIV, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
669✔
461
   return jit_value_from_reg(r);
669✔
462
}
463

464
static jit_value_t j_fdiv(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
216✔
465
{
466
   jit_reg_t r = irgen_alloc_reg(g);
216✔
467
   irgen_emit_binary(g, J_FDIV, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
216✔
468
   return jit_value_from_reg(r);
216✔
469
}
470

471
static jit_value_t j_sub(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
83,013✔
472
{
473
   jit_reg_t r = irgen_alloc_reg(g);
83,013✔
474
   irgen_emit_binary(g, J_SUB, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
83,013✔
475
   return jit_value_from_reg(r);
83,013✔
476
}
477

478
static jit_value_t j_subs(jit_irgen_t *g, jit_size_t sz, jit_cc_t cc,
2,039✔
479
                          jit_value_t lhs, jit_value_t rhs)
480
{
481
   jit_reg_t r = irgen_alloc_reg(g);
2,039✔
482
   irgen_emit_binary(g, J_SUB, sz, cc, r, lhs, rhs);
2,039✔
483
   g->flags = MIR_NULL_VALUE;
2,039✔
484
   return jit_value_from_reg(r);
2,039✔
485
}
486

487
static jit_value_t j_fsub(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
286✔
488
{
489
   jit_reg_t r = irgen_alloc_reg(g);
286✔
490
   irgen_emit_binary(g, J_FSUB, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
286✔
491
   return jit_value_from_reg(r);
286✔
492
}
493

494
static void j_cmp(jit_irgen_t *g, jit_cc_t cc, jit_value_t lhs, jit_value_t rhs)
187,441✔
495
{
496
   irgen_emit_binary(g, J_CMP, JIT_SZ_UNSPEC, cc, JIT_REG_INVALID, lhs, rhs);
187,441✔
497
   g->flags = MIR_NULL_VALUE;
187,441✔
498
}
187,441✔
499

500
static void j_ccmp(jit_irgen_t *g, jit_cc_t cc, jit_value_t lhs, jit_value_t rhs)
14,009✔
501
{
502
   irgen_emit_binary(g, J_CCMP, JIT_SZ_UNSPEC, cc, JIT_REG_INVALID, lhs, rhs);
14,009✔
503
   g->flags = MIR_NULL_VALUE;
14,009✔
504
}
14,009✔
505

506
static void j_fcmp(jit_irgen_t *g, jit_cc_t cc, jit_value_t lhs,
2,294✔
507
                   jit_value_t rhs)
508
{
509
   irgen_emit_binary(g, J_FCMP, JIT_SZ_UNSPEC, cc, JIT_REG_INVALID, lhs, rhs);
2,294✔
510
   g->flags = MIR_NULL_VALUE;
2,294✔
511
}
2,294✔
512

513
static void j_fccmp(jit_irgen_t *g, jit_cc_t cc, jit_value_t lhs,
397✔
514
                    jit_value_t rhs)
515
{
516
   irgen_emit_binary(g, J_FCCMP, JIT_SZ_UNSPEC, cc, JIT_REG_INVALID, lhs, rhs);
397✔
517
   g->flags = MIR_NULL_VALUE;
397✔
518
}
397✔
519

520
static jit_value_t j_cset(jit_irgen_t *g)
54,713✔
521
{
522
   jit_reg_t r = irgen_alloc_reg(g);
54,713✔
523
   irgen_emit_nullary(g, J_CSET, JIT_CC_NONE, r);
54,713✔
524
   return jit_value_from_reg(r);
54,713✔
525
}
526

527
static jit_value_t j_uload(jit_irgen_t *g, jit_size_t sz, jit_value_t addr)
18,751✔
528
{
529
   assert(jit_value_is_addr(addr));
18,751✔
530
   jit_reg_t r = irgen_alloc_reg(g);
18,751✔
531
   irgen_emit_unary(g, J_ULOAD, sz, JIT_CC_NONE, r, addr);
18,751✔
532
   return jit_value_from_reg(r);
18,751✔
533
}
534

535
static jit_value_t j_load(jit_irgen_t *g, jit_size_t sz, jit_value_t addr)
226,854✔
536
{
537
   jit_reg_t r = irgen_alloc_reg(g);
226,854✔
538
   irgen_emit_unary(g, J_LOAD, sz, JIT_CC_NONE, r, addr);
226,854✔
539
   return jit_value_from_reg(r);
226,854✔
540
}
541

542
static void j_store(jit_irgen_t *g, jit_size_t sz, jit_value_t value,
140,658✔
543
                    jit_value_t addr)
544
{
545
   assert(!jit_value_is_addr(value));
140,658✔
546
   irgen_emit_binary(g, J_STORE, sz, JIT_CC_NONE, JIT_REG_INVALID, value, addr);
140,658✔
547
}
140,658✔
548

549
static void j_mov(jit_irgen_t *g, jit_reg_t dest, jit_value_t value)
124,513✔
550
{
551
   assert(!jit_value_is_addr(value));
124,513✔
552
   irgen_emit_unary(g, J_MOV, JIT_SZ_UNSPEC, JIT_CC_NONE, dest, value);
124,513✔
553
}
124,513✔
554

555
static jit_value_t j_lea(jit_irgen_t *g, jit_value_t addr)
31,727✔
556
{
557
   assert(jit_value_is_addr(addr));
31,727✔
558
   jit_reg_t r = irgen_alloc_reg(g);
31,727✔
559
   irgen_emit_unary(g, J_LEA, JIT_SZ_UNSPEC, JIT_CC_NONE, r, addr);
31,727✔
560
   return jit_value_from_reg(r);
31,727✔
561
}
562

563
static jit_value_t j_scvtf(jit_irgen_t *g, jit_value_t value)
253✔
564
{
565
   jit_reg_t r = irgen_alloc_reg(g);
253✔
566
   irgen_emit_unary(g, J_SCVTF, JIT_SZ_UNSPEC, JIT_CC_NONE, r, value);
253✔
567
   return jit_value_from_reg(r);
253✔
568
}
569

570
static jit_value_t j_fcvtns(jit_irgen_t *g, jit_value_t value)
103✔
571
{
572
   jit_reg_t r = irgen_alloc_reg(g);
103✔
573
   irgen_emit_unary(g, J_FCVTNS, JIT_SZ_UNSPEC, JIT_CC_NONE, r, value);
103✔
574
   return jit_value_from_reg(r);
103✔
575
}
576

577
static jit_value_t j_csel(jit_irgen_t *g, jit_value_t iftrue,
85,644✔
578
                          jit_value_t iffalse)
579
{
580
   jit_reg_t r = irgen_alloc_reg(g);
85,644✔
581
   irgen_emit_binary(g, J_CSEL, JIT_SZ_UNSPEC, JIT_CC_NONE, r, iftrue, iffalse);
85,644✔
582
   return jit_value_from_reg(r);
85,644✔
583
}
584

585
static jit_value_t j_clamp(jit_irgen_t *g, jit_value_t value)
35,532✔
586
{
587
   jit_reg_t r = irgen_alloc_reg(g);
35,532✔
588
   irgen_emit_unary(g, J_CLAMP, JIT_SZ_UNSPEC, JIT_CC_NONE, r, value);
35,532✔
589
   return jit_value_from_reg(r);
35,532✔
590
}
591

592
#if 0
593
static void macro_copy(jit_irgen_t *g, jit_value_t dest, jit_value_t src,
594
                       jit_reg_t count)
595
{
596
   irgen_emit_binary(g, MACRO_COPY, JIT_SZ_UNSPEC, JIT_CC_NONE,
597
                     count, dest, src);
598
}
599
#endif
600

601
static void macro_move(jit_irgen_t *g, jit_value_t dest, jit_value_t src,
15,649✔
602
                       jit_reg_t count)
603
{
604
   irgen_emit_binary(g, MACRO_MOVE, JIT_SZ_UNSPEC, JIT_CC_NONE,
15,649✔
605
                     count, dest, src);
606
}
15,649✔
607

608
static void macro_bzero(jit_irgen_t *g, jit_value_t dest, jit_reg_t count)
3,876✔
609
{
610
   assert(jit_value_is_addr(dest));
3,876✔
611
   irgen_emit_unary(g, MACRO_BZERO, JIT_SZ_UNSPEC, JIT_CC_NONE,
3,876✔
612
                    count, dest);
613
}
3,876✔
614

615
static void macro_memset(jit_irgen_t *g, jit_size_t sz, jit_value_t dest,
1,673✔
616
                         jit_value_t value, jit_reg_t count)
617
{
618
   assert(jit_value_is_addr(dest));
1,673✔
619
   irgen_emit_binary(g, MACRO_MEMSET, sz, JIT_CC_NONE, count, dest, value);
1,673✔
620
}
1,673✔
621

622
static jit_value_t macro_galloc(jit_irgen_t *g, jit_value_t bytes)
582✔
623
{
624
   jit_reg_t r = irgen_alloc_reg(g);
582✔
625
   irgen_emit_unary(g, MACRO_GALLOC, JIT_SZ_UNSPEC, JIT_CC_NONE, r, bytes);
582✔
626
   return jit_value_from_reg(r);
582✔
627
}
628

629
static jit_value_t macro_lalloc(jit_irgen_t *g, jit_value_t bytes)
23,130✔
630
{
631
   jit_reg_t r = irgen_alloc_reg(g);
23,130✔
632
   irgen_emit_unary(g, MACRO_LALLOC, JIT_SZ_UNSPEC, JIT_CC_NONE, r, bytes);
23,130✔
633
   return jit_value_from_reg(r);
23,130✔
634
}
635

636
static jit_value_t macro_salloc(jit_irgen_t *g, size_t size)
12,851✔
637
{
638
   jit_reg_t r = irgen_alloc_reg(g);
12,851✔
639
   jit_value_t arg1 = jit_value_from_int64(g->func->framesz);
12,851✔
640
   jit_value_t arg2 = jit_value_from_int64(size);
12,851✔
641
   irgen_emit_binary(g, MACRO_SALLOC, JIT_SZ_UNSPEC, JIT_CC_NONE,
12,851✔
642
                     r, arg1, arg2);
643
   g->func->framesz += ALIGN_UP(size, 8);
12,851✔
644
   return jit_value_from_reg(r);
12,851✔
645
}
646

647
static void macro_exit(jit_irgen_t *g, jit_exit_t exit)
123,163✔
648
{
649
   irgen_emit_unary(g, MACRO_EXIT, JIT_SZ_UNSPEC, JIT_CC_NONE, JIT_REG_INVALID,
123,163✔
650
                    jit_value_from_exit(exit));
651
   g->flags = MIR_NULL_VALUE;
123,163✔
652
}
123,163✔
653

654
static jit_value_t macro_fexp(jit_irgen_t *g, jit_value_t lhs, jit_value_t rhs)
72✔
655
{
656
   jit_reg_t r = irgen_alloc_reg(g);
72✔
657
   irgen_emit_binary(g, MACRO_FEXP, JIT_SZ_UNSPEC, JIT_CC_NONE, r, lhs, rhs);
72✔
658
   return jit_value_from_reg(r);
72✔
659
}
660

661
static jit_value_t macro_exp(jit_irgen_t *g, jit_size_t sz, jit_cc_t cc,
531✔
662
                             jit_value_t lhs, jit_value_t rhs)
663
{
664
   jit_reg_t r = irgen_alloc_reg(g);
531✔
665
   irgen_emit_binary(g, MACRO_EXP, sz, cc, r, lhs, rhs);
531✔
666
   return jit_value_from_reg(r);
531✔
667
}
668

669
static jit_value_t macro_getpriv(jit_irgen_t *g, jit_handle_t handle)
22,496✔
670
{
671
   jit_reg_t r = irgen_alloc_reg(g);
22,496✔
672
   irgen_emit_unary(g, MACRO_GETPRIV, JIT_SZ_UNSPEC, JIT_CC_NONE, r,
22,496✔
673
                    jit_value_from_handle(handle));
674
   return jit_value_from_reg(r);
22,496✔
675
}
676

677
static void macro_putpriv(jit_irgen_t *g, jit_handle_t handle, jit_value_t ptr)
11,099✔
678
{
679
   irgen_emit_binary(g, MACRO_PUTPRIV, JIT_SZ_UNSPEC, JIT_CC_NONE,
11,099✔
680
                     JIT_REG_INVALID, jit_value_from_handle(handle), ptr);
681
}
11,099✔
682

683
static void macro_case(jit_irgen_t *g, jit_reg_t test, jit_value_t cmp,
18,153✔
684
                       irgen_label_t *l)
685
{
686
   jit_ir_t *ir = irgen_emit_binary(g, MACRO_CASE, JIT_SZ_UNSPEC, JIT_CC_NONE,
18,153✔
687
                                    test, cmp, jit_value_from_label(l));
688
   irgen_patch_label(g, ir, l);
18,153✔
689
}
18,153✔
690

691
static void macro_trim(jit_irgen_t *g)
3,047✔
692
{
693
   irgen_emit_nullary(g, MACRO_TRIM, JIT_CC_NONE, JIT_REG_INVALID);
3,047✔
694
}
3,047✔
695

696
static void macro_reexec(jit_irgen_t *g)
259✔
697
{
698
   irgen_emit_nullary(g, MACRO_REEXEC, JIT_CC_NONE, JIT_REG_INVALID);
259✔
699
   g->flags = MIR_NULL_VALUE;
259✔
700
}
259✔
701

702
static void macro_sadd(jit_irgen_t *g, jit_size_t sz, jit_value_t addr,
2,296✔
703
                       jit_value_t addend)
704
{
705
   irgen_emit_binary(g, MACRO_SADD, sz, JIT_CC_NONE, JIT_REG_INVALID,
2,296✔
706
                     addr, addend);
707
}
2,296✔
708

709
////////////////////////////////////////////////////////////////////////////////
710
// MIR to JIT IR lowering
711

712
static int irgen_slots_for_type(jit_irgen_t *g, mir_type_t type)
333,102✔
713
{
714
   if (mir_is_null(type))
333,102✔
715
      return 1;   // Untyped constants
716

717
   switch (mir_get_class(g->mu, type)) {
313,192✔
718
   case MIR_TYPE_UARRAY:
62,253✔
719
      // Always passed around scalarised
720
      if (mir_get_class(g->mu, mir_get_elem(g->mu, type)) == MIR_TYPE_SIGNAL)
62,253✔
721
         return 2 + mir_get_dims(g->mu, type) * 2;
120✔
722
      else
723
         return 1 + mir_get_dims(g->mu, type) * 2;
62,133✔
724
   case MIR_TYPE_SIGNAL:
725
      // Signal pointer plus offset
726
      return 2;
727
   case MIR_TYPE_CLOSURE:
728
      // Function pointer, context
729
      return 2;
UNCOV
730
   case MIR_TYPE_RESOLUTION:
×
731
      // Closure slots plus left, nlits, and flags (this is silly)
UNCOV
732
      return 5;
×
733
   default:
239,426✔
734
      // Passed by pointer or fits in 64-bit register
735
      return 1;
239,426✔
736
   }
737
}
738

739
static int irgen_repr_bits(mir_repr_t repr)
370,885✔
740
{
741
   switch (repr) {
370,885✔
742
   case MIR_REPR_U1: return 1;
743
   case MIR_REPR_U8: case MIR_REPR_I8: return 8;
744
   case MIR_REPR_U16: case MIR_REPR_I16: return 16;
745
   case MIR_REPR_U32: case MIR_REPR_I32: return 32;
746
   case MIR_REPR_U64: case MIR_REPR_I64: return 64;
747
   default: return -1;
748
   }
749
}
750

751
static bool irgen_repr_signed(mir_repr_t repr)
47,399✔
752
{
753
   return repr == MIR_REPR_I8 || repr == MIR_REPR_I16
47,399✔
754
      || repr == MIR_REPR_I32 || repr == MIR_REPR_I64;
47,399✔
755
}
756

757
static int irgen_align_of(jit_irgen_t *g, mir_type_t type)
299,766✔
758
{
759
   switch (mir_get_class(g->mu, type)) {
299,766✔
760
   case MIR_TYPE_INT:
114,180✔
761
   case MIR_TYPE_OFFSET:
762
      {
763
         const int bits = irgen_repr_bits(mir_get_repr(g->mu, type));
114,180✔
764
         return ALIGN_UP(bits, 8) / 8;
114,180✔
765
      }
766
   case MIR_TYPE_REAL:
767
   case MIR_TYPE_RECORD:
768
      return sizeof(double);
769
   case MIR_TYPE_POINTER:
770
   case MIR_TYPE_ACCESS:
771
   case MIR_TYPE_UARRAY:
772
   case MIR_TYPE_SIGNAL:
773
   case MIR_TYPE_CONTEXT:
774
   case MIR_TYPE_FILE:
775
   case MIR_TYPE_TRIGGER:
776
      return sizeof(void *);
777
   case MIR_TYPE_CARRAY:
39,228✔
778
      return irgen_align_of(g, mir_get_elem(g->mu, type));
39,228✔
UNCOV
779
   default:
×
780
      fatal_trace("cannot handle type %d in irgen_align_of",
UNCOV
781
                  mir_get_class(g->mu, type));
×
782
   }
783
}
784

785
static int irgen_size_bits(jit_irgen_t *g, mir_type_t type)
261,680✔
786
{
787
   switch (mir_get_class(g->mu, type)) {
261,680✔
788
   case MIR_TYPE_INT:
256,705✔
789
   case MIR_TYPE_OFFSET:
790
      return irgen_repr_bits(mir_get_repr(g->mu, type));
256,705✔
791
   case MIR_TYPE_REAL:
792
      return sizeof(double) * 8;
793
   case MIR_TYPE_POINTER:
794
   case MIR_TYPE_ACCESS:
795
   case MIR_TYPE_CONTEXT:
796
   case MIR_TYPE_FILE:
797
   case MIR_TYPE_TRIGGER:
798
      return sizeof(void *) * 8;
UNCOV
799
   default:
×
800
      fatal_trace("cannot handle type %d in irgen_size_bits",
UNCOV
801
                  mir_get_class(g->mu, type));
×
802
   }
803
}
804

805
static int irgen_size_bytes(jit_irgen_t *g, mir_type_t type)
342,478✔
806
{
807
   switch (mir_get_class(g->mu, type)) {
342,478✔
808
   case MIR_TYPE_INT:
167,776✔
809
   case MIR_TYPE_OFFSET:
810
      {
811
         const int bits = irgen_size_bits(g, type);
167,776✔
812
         return ALIGN_UP(bits, 8) / 8;
167,776✔
813
      }
814

815
   case MIR_TYPE_REAL:
816
      return sizeof(double);
817

818
   case MIR_TYPE_CARRAY:
34,747✔
819
      {
820
         mir_type_t elem = mir_get_elem(g->mu, type);
34,747✔
821
         return mir_get_size(g->mu, type) * irgen_size_bytes(g, elem);
34,747✔
822
      }
823

824
   case MIR_TYPE_RECORD:
21,619✔
825
      {
826
         // TODO: cache this
827
         size_t nfields, bytes = 0;
21,619✔
828
         const mir_type_t *fields = mir_get_fields(g->mu, type, &nfields);
21,619✔
829
         for (int i = 0; i < nfields; i++) {
97,160✔
830
            const int fb = irgen_size_bytes(g, fields[i]);
75,541✔
831
            const int align = irgen_align_of(g, fields[i]);
75,541✔
832

833
            bytes = ALIGN_UP(bytes, align);
75,541✔
834
            bytes += fb;
75,541✔
835
         }
836

837
         return ALIGN_UP(bytes, sizeof(double));
21,619✔
838
      }
839

840
   case MIR_TYPE_UARRAY:
16,129✔
841
      {
842
         const int ndims = mir_get_dims(g->mu, type);
16,129✔
843
         if (mir_get_class(g->mu, mir_get_elem(g->mu, type)) == MIR_TYPE_SIGNAL)
16,129✔
844
            return 2*sizeof(void *) + 2 * sizeof(int64_t) * ndims;
5,290✔
845
         else
846
            return sizeof(void *) + 2 * sizeof(int64_t) * ndims;
10,839✔
847
      }
848

849
   case MIR_TYPE_ACCESS:
850
   case MIR_TYPE_POINTER:
851
   case MIR_TYPE_CONTEXT:
852
   case MIR_TYPE_FILE:
853
   case MIR_TYPE_TRIGGER:
854
      return sizeof(void *);
855

856
   case MIR_TYPE_SIGNAL:
81,434✔
857
      return sizeof(void *) + sizeof(int32_t);
81,434✔
858

UNCOV
859
   default:
×
860
      fatal_trace("cannot handle type %d in irgen_size_bytes",
UNCOV
861
                  mir_get_class(g->mu, type));
×
862
   }
863
}
864

865
static jit_size_t irgen_jit_size(jit_irgen_t *g, mir_type_t type)
93,904✔
866
{
867
   const int bits = irgen_size_bits(g, type);
93,904✔
868
   switch (bits) {
93,904✔
869
   case 1:
870
   case 8: return JIT_SZ_8;
871
   case 16: return JIT_SZ_16;
51✔
872
   case 32: return JIT_SZ_32;
35,397✔
873
   case 64: return JIT_SZ_64;
25,495✔
UNCOV
874
   default:
×
875
      fatal_trace("illegal operand size %d", bits);
876
   }
877
}
878

879
static jit_value_t irgen_get_value(jit_irgen_t *g, mir_value_t value)
2,678,024✔
880
{
881
   assert(!mir_is_null(value));
2,678,024✔
882

883
   switch (value.tag) {
2,678,024✔
884
   case MIR_TAG_NODE:
998,997✔
885
      assert(g->map[value.id].kind != JIT_VALUE_INVALID);
998,997✔
886
      return g->map[value.id];
998,997✔
887
   case MIR_TAG_CONST:
1,508,827✔
888
      {
889
         int64_t cval;
1,508,827✔
890
         if (mir_get_const(g->mu, value, &cval))
1,508,827✔
891
            return jit_value_from_int64(cval);
1,508,827✔
892

893
         should_not_reach_here();
894
      }
895
   case MIR_TAG_VAR:
116,425✔
896
      return g->vars[value.id];
116,425✔
897
   case MIR_TAG_PARAM:
53,775✔
898
      return g->params[value.id];
53,775✔
UNCOV
899
   default:
×
900
      DEBUG_ONLY(mir_dump(g->mu));
×
901
      should_not_reach_here();
902
   }
903
}
904

905
static jit_value_t irgen_get_arg(jit_irgen_t *g, mir_value_t n, int arg)
2,290,224✔
906
{
907
   return irgen_get_value(g, mir_get_arg(g->mu, n, arg));
2,290,224✔
908
}
909

910
static unsigned irgen_get_enum(jit_irgen_t *g, mir_value_t n, int arg)
33,541✔
911
{
912
   mir_value_t value = mir_get_arg(g->mu, n, arg);
33,541✔
913
   assert(value.tag == MIR_TAG_ENUM);
33,541✔
914
   return value.id;
33,541✔
915
}
916

917
static int64_t irgen_get_const(jit_irgen_t *g, mir_value_t n, int arg)
217,206✔
918
{
919
   mir_value_t value = mir_get_arg(g->mu, n, arg);
217,206✔
920

921
   int64_t result;
217,206✔
922
   if (mir_get_const(g->mu, value, &result))
217,206✔
923
      return result;
217,206✔
924

925
#ifdef DEBUG
UNCOV
926
   mir_dump(g->mu);
×
927
   fatal_trace("argument %d is not constant", arg);
928
#else
929
   should_not_reach_here();
930
#endif
931
}
932

933
static jit_value_t irgen_lea(jit_irgen_t *g, jit_value_t addr)
62,402✔
934
{
935
   switch (addr.kind) {
62,402✔
936
   case JIT_ADDR_REG:
21,793✔
937
      if (addr.disp == 0)
21,793✔
938
         return jit_value_from_reg(addr.reg);
409✔
939
      else
940
         return j_lea(g, addr);
21,384✔
941
   case JIT_ADDR_CPOOL:
10,343✔
942
      return j_lea(g, addr);
10,343✔
943
   case JIT_ADDR_ABS:
2,059✔
944
      return jit_value_from_int64(addr.int64);
2,059✔
945
   case JIT_VALUE_REG:
28,207✔
946
   case JIT_VALUE_INT64:
947
      return addr;
28,207✔
UNCOV
948
   default:
×
949
      fatal_trace("cannot load address of value kind %d", addr.kind);
950
   }
951
}
952

953
static jit_reg_t irgen_as_reg(jit_irgen_t *g, jit_value_t value)
15,667✔
954
{
955
   switch (value.kind) {
15,667✔
956
   case JIT_VALUE_REG:
13,884✔
957
      return value.reg;
13,884✔
958
   case JIT_ADDR_REG:
3✔
959
   case JIT_ADDR_CPOOL:
960
   case JIT_ADDR_ABS:
961
      return jit_value_as_reg(irgen_lea(g, value));
3✔
962
   default:
1,780✔
963
      {
964
         jit_reg_t r = irgen_alloc_reg(g);
1,780✔
965
         j_mov(g, r, value);
1,780✔
966
         return r;
1,780✔
967
      }
968
   }
969
}
970

971
static jit_value_t irgen_is_scalar(jit_irgen_t *g, mir_value_t n, int arg)
27,653✔
972
{
973
   mir_value_t value = mir_get_arg(g->mu, n, arg);
27,653✔
974
   return jit_value_from_int64(!mir_is(g->mu, value, MIR_TYPE_POINTER));
27,653✔
975
}
976

977
static jit_value_t irgen_get_context(jit_irgen_t *g)
53,206✔
978
{
979
   if (g->statereg.kind != JIT_VALUE_INVALID)
53,206✔
980
      return j_load(g, JIT_SZ_PTR, jit_addr_from_value(g->statereg, 0));
24,117✔
981
   else if (g->contextarg.kind != JIT_VALUE_INVALID)
29,089✔
982
      return g->contextarg;
20,983✔
983
   else
984
      return g->params[mir_get_param(g->mu, 0).id];
8,106✔
985
}
986

987
static size_t irgen_append_cpool(jit_irgen_t *g, size_t sz, int align)
23,530✔
988
{
989
   if (g->cpoolptr + sz + align - 1 > g->func->cpoolsz) {
23,530✔
990
      g->func->cpoolsz = MAX(128, MAX((g->func->cpoolsz * 3) / 2,
9,612✔
991
                                      g->cpoolptr + sz + align - 1));
992
      g->func->cpool = xrealloc(g->func->cpool, g->func->cpoolsz);
9,612✔
993
      g->func->owns_cpool = true;
9,612✔
994
   }
995

996
   const size_t result = ALIGN_UP(g->cpoolptr, align);
23,530✔
997
   g->oldptr = result;
23,530✔
998
   g->cpoolptr = result + sz;
23,530✔
999
   return result;
23,530✔
1000
}
1001

1002
static jit_value_t irgen_dedup_cpool(jit_irgen_t *g)
21,392✔
1003
{
1004
   unsigned char *dup = memmem(g->func->cpool, MIN(g->oldptr, DEDUP_PREFIX),
21,392✔
1005
                               g->func->cpool + g->oldptr,
21,392✔
1006
                               g->cpoolptr - g->oldptr);
21,392✔
1007
   if (dup != NULL) {
21,392✔
1008
      g->cpoolptr = g->oldptr;
2,845✔
1009
      return jit_value_from_cpool_addr(dup - g->func->cpool);
2,845✔
1010
   }
1011
   else
1012
      return jit_value_from_cpool_addr(g->oldptr);
18,547✔
1013
}
1014

1015
static void irgen_emit_debuginfo(jit_irgen_t *g, mir_value_t n)
1,132,526✔
1016
{
1017
   jit_value_t arg1 = jit_value_from_loc(mir_get_loc(g->mu, n));
1,132,526✔
1018

1019
   jit_value_t arg2 = {
1,132,526✔
1020
      .kind = JIT_VALUE_VPOS,
1021
      .vpos = { .block = g->curblock.id, .op = n.id }
1,132,526✔
1022
   };
1023

1024
   if (g->func->nirs > 0 && g->func->irbuf[g->func->nirs - 1].op == J_DEBUG) {
1,132,526✔
1025
      jit_ir_t *prev = &(g->func->irbuf[g->func->nirs - 1]);
342,479✔
1026
      prev->arg1 = arg1;
342,479✔
1027
      prev->arg2 = arg2;
342,479✔
1028
   }
1029
   else
1030
      irgen_emit_binary(g, J_DEBUG, JIT_SZ_UNSPEC, JIT_CC_NONE,
790,047✔
1031
                        JIT_REG_INVALID, arg1, arg2);
1032
}
1,132,526✔
1033

1034
static ffi_type_t irgen_ffi_type(jit_irgen_t *g, mir_type_t type)
38,236✔
1035
{
1036
   if (mir_is_null(type))
38,236✔
1037
      return FFI_VOID;
1038

1039
   switch (mir_get_class(g->mu, type)) {
38,236✔
1040
   case MIR_TYPE_INT:
10,252✔
1041
   case MIR_TYPE_OFFSET:
1042
      switch (mir_get_repr(g->mu, type)) {
10,252✔
1043
      case MIR_REPR_U1:
1044
      case MIR_REPR_U8:
1045
         return FFI_UINT8;
1046
      case MIR_REPR_I8:
1047
         return FFI_INT8;
1048
      case MIR_REPR_I16:
1049
         return FFI_INT16;
1050
      case MIR_REPR_U16:
1051
         return FFI_UINT16;
1052
      case MIR_REPR_I32:
1053
         return FFI_INT32;
1054
      case MIR_REPR_U32:
1055
         return FFI_UINT32;
1056
      default:
1057
         return FFI_INT64;
1058
      }
1059
   case MIR_TYPE_REAL:
1060
      return FFI_FLOAT;
1061
   case MIR_TYPE_CARRAY:
14,594✔
1062
   case MIR_TYPE_RECORD:
1063
   case MIR_TYPE_POINTER:
1064
   case MIR_TYPE_CONTEXT:
1065
   case MIR_TYPE_ACCESS:
1066
   case MIR_TYPE_FILE:
1067
   case MIR_TYPE_LOCUS:
1068
   case MIR_TYPE_CONVERSION:
1069
      return FFI_POINTER;
14,594✔
1070
   case MIR_TYPE_UARRAY:
12,383✔
1071
      return FFI_UARRAY;
12,383✔
1072
   case MIR_TYPE_SIGNAL:
154✔
1073
      return FFI_SIGNAL;
154✔
UNCOV
1074
   default:
×
1075
      fatal_trace("cannot handle type %d in irgen_ffi_type",
UNCOV
1076
                  mir_get_class(g->mu, type));
×
1077
   }
1078
}
1079

1080
static jit_handle_t irgen_get_handle(jit_irgen_t *g, mir_value_t n, int arg)
71,097✔
1081
{
1082
   ident_t func = mir_get_name(g->mu, mir_get_arg(g->mu, n, arg));
71,097✔
1083
   jit_handle_t handle = jit_lazy_compile(g->func->jit, func);
71,097✔
1084
   if (handle == JIT_HANDLE_INVALID)
71,097✔
UNCOV
1085
      fatal_at(mir_get_loc(g->mu, n), "missing definition for %s", istr(func));
×
1086

1087
   return handle;
71,097✔
1088
}
1089

1090
static jit_value_t irgen_state_ptr(jit_irgen_t *g)
17,754✔
1091
{
1092
   assert(g->statereg.kind != JIT_VALUE_INVALID);
17,754✔
1093
   return jit_addr_from_value(g->statereg, 2 * sizeof(void *));
17,754✔
1094
}
1095

1096
static jit_value_t irgen_pcall_ptr(jit_irgen_t *g)
2,625✔
1097
{
1098
   assert(g->statereg.kind != JIT_VALUE_INVALID);
2,625✔
1099
   return jit_addr_from_value(g->statereg, 1 * sizeof(void *));
2,625✔
1100
}
1101

1102
static void irgen_op_null(jit_irgen_t *g, mir_value_t n)
2,712✔
1103
{
1104
   g->map[n.id] = jit_null_ptr();
2,712✔
1105
}
2,712✔
1106

1107
static void irgen_op_const(jit_irgen_t *g, mir_value_t n)
6,763✔
1108
{
1109
   int64_t cval;
6,763✔
1110
   if (mir_get_const(g->mu, n, &cval))
6,763✔
1111
      g->map[n.id] = jit_value_from_int64(cval);
6,763✔
1112
   else
1113
      should_not_reach_here();
1114
}
6,763✔
1115

1116
static void irgen_op_const_real(jit_irgen_t *g, mir_value_t n)
20,897✔
1117
{
1118
   double val;
20,897✔
1119
   if (mir_get_const_real(g->mu, n, &val))
20,897✔
1120
      g->map[n.id] = jit_value_from_double(val);
20,897✔
1121
   else
1122
      should_not_reach_here();
1123
}
20,897✔
1124

1125
static void irgen_copy_const(jit_irgen_t *g, unsigned char *p,
1,188,869✔
1126
                             jit_value_t value, int bytes)
1127
{
1128
   switch (value.kind) {
1,188,869✔
1129
   case JIT_VALUE_INT64:
1,172,047✔
1130
      switch (bytes) {
1,172,047✔
1131
      case 1: *(uint8_t *)p = (uint8_t)value.int64; break;
1,160,706✔
1132
      case 2: *(uint16_t *)p = (uint16_t)value.int64; break;
780✔
1133
      case 4: *(uint32_t *)p = (uint32_t)value.int64; break;
8,299✔
1134
      case 8: *(uint64_t *)p = (uint64_t)value.int64; break;
2,262✔
UNCOV
1135
      default:
×
1136
         fatal_trace("cannot handle value size %d", bytes);
1137
      }
1138
      break;
1139

1140
   case JIT_VALUE_DOUBLE:
15,200✔
1141
      assert(bytes == sizeof(double));
15,200✔
1142
      *(double *)p = value.dval;
15,200✔
1143
      break;
15,200✔
1144

1145
   case JIT_ADDR_CPOOL:
1,517✔
1146
      assert(value.int64 >= 0 && value.int64 + bytes <= g->func->cpoolsz);
1,517✔
1147
      memcpy(p, g->func->cpool + value.int64, bytes);
1,517✔
1148
      break;
1149

1150
   case JIT_ADDR_ABS:
105✔
1151
      assert(value.int64 == 0);
105✔
1152
      switch (bytes) {
105✔
1153
      case sizeof(void *): *(uintptr_t *)p = (uintptr_t)value.int64; break;
99✔
1154
      case 0: break;
1155
      default: should_not_reach_here();
1156
      }
1157
      break;
1158

UNCOV
1159
   default:
×
1160
      fatal_trace("cannot handle value kind %d", value.kind);
1161
   }
1162
}
1,188,869✔
1163

1164
static void irgen_op_const_array(jit_irgen_t *g, mir_value_t n)
21,165✔
1165
{
1166
   mir_type_t type = mir_get_type(g->mu, n);
21,165✔
1167
   mir_type_t elem = mir_get_elem(g->mu, type);
21,165✔
1168

1169
   const int elemsz = irgen_size_bytes(g, elem);
21,165✔
1170
   const int align = irgen_align_of(g, elem);
21,165✔
1171
   const int count = mir_get_size(g->mu, type);
21,165✔
1172

1173
   if (count > 0) {
21,165✔
1174
      const size_t offset = irgen_append_cpool(g, elemsz * count, align);
21,113✔
1175

1176
      unsigned char *p = g->func->cpool + offset;
21,113✔
1177
      for (int i = 0; i < count; i++, p += elemsz) {
1,180,051✔
1178
         jit_value_t elem = irgen_get_arg(g, n, i);
1,158,938✔
1179
         irgen_copy_const(g, p, elem, elemsz);
1,158,938✔
1180
      }
1181

1182
      g->map[n.id] = irgen_dedup_cpool(g);
21,113✔
1183
   }
1184
   else
1185
      g->map[n.id] = jit_null_ptr();
52✔
1186
}
21,165✔
1187

1188
static void irgen_op_const_rep(jit_irgen_t *g, mir_value_t n)
279✔
1189
{
1190
   mir_type_t elem = mir_get_elem(g->mu, mir_get_type(g->mu, n));
279✔
1191

1192
   const int count = irgen_get_const(g, n, 1);
279✔
1193
   jit_value_t value = irgen_get_arg(g, n, 0);
279✔
1194

1195
   const int elemsz = irgen_size_bytes(g, elem);
279✔
1196
   const int align = irgen_align_of(g, elem);
279✔
1197

1198
   const size_t offset = irgen_append_cpool(g, elemsz * count, align);
279✔
1199

1200
   unsigned char *p = g->func->cpool + offset;
279✔
1201
   for (int i = 0; i < count; i++, p += elemsz)
24,800✔
1202
      irgen_copy_const(g, p, value, elemsz);
24,521✔
1203

1204
   g->map[n.id] = irgen_dedup_cpool(g);
279✔
1205
}
279✔
1206

1207
static void irgen_op_const_record(jit_irgen_t *g, mir_value_t n)
2,138✔
1208
{
1209
   mir_type_t type = mir_get_type(g->mu, n);
2,138✔
1210

1211
   size_t nfields;
2,138✔
1212
   const mir_type_t *fields = mir_get_fields(g->mu, type, &nfields);
2,138✔
1213

1214
   const int sz = irgen_size_bytes(g, type);
2,138✔
1215
   const int align = irgen_align_of(g, type);
2,138✔
1216
   const size_t offset = irgen_append_cpool(g, sz, align);
2,138✔
1217

1218
   unsigned char *p = g->func->cpool + offset;
2,138✔
1219
   for (int i = 0; i < nfields; i++) {
7,548✔
1220
      jit_value_t elem = irgen_get_arg(g, n, i);
5,410✔
1221

1222
      const int bytes = irgen_size_bytes(g, fields[i]);
5,410✔
1223
      const int align = irgen_align_of(g, fields[i]);
5,410✔
1224

1225
      while (p != ALIGN_UP(p, align))
6,829✔
1226
         *p++ = 0;   // Pad to field alignment
1,419✔
1227

1228
      irgen_copy_const(g, p, elem, bytes);
5,410✔
1229
      p += bytes;
5,410✔
1230
   }
1231
   assert(g->func->cpool + offset + sz - p < sizeof(double));
2,138✔
1232

1233
   g->map[n.id] = jit_value_from_cpool_addr(offset);
2,138✔
1234
}
2,138✔
1235

1236
static void irgen_op_address_of(jit_irgen_t *g, mir_value_t n)
22,584✔
1237
{
1238
   // No-op
1239
   g->map[n.id] = irgen_get_arg(g, n, 0);
22,584✔
1240
}
22,584✔
1241

1242
static void irgen_op_copy(jit_irgen_t *g, mir_value_t n)
15,649✔
1243
{
1244
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
15,649✔
1245
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
15,649✔
1246

1247
   mir_type_t elem = mir_get_type(g->mu, n);
15,649✔
1248

1249
   jit_value_t bytes;
15,649✔
1250
   if (mir_count_args(g->mu, n) > 2) {
15,649✔
1251
      jit_value_t arg2 = irgen_get_arg(g, n, 2);
13,869✔
1252

1253
      const int scale = irgen_size_bytes(g, elem);
13,869✔
1254
      bytes = j_mul(g, arg2, jit_value_from_int64(scale));
13,869✔
1255
   }
1256
   else
1257
      bytes = jit_value_from_int64(irgen_size_bytes(g, elem));
1,780✔
1258

1259
   jit_value_t dest = jit_addr_from_value(arg0, 0);
15,649✔
1260
   jit_value_t src = jit_addr_from_value(arg1, 0);
15,649✔
1261

1262
   macro_move(g, dest, src, irgen_as_reg(g, bytes));
15,649✔
1263
}
15,649✔
1264

1265
static void irgen_op_set(jit_irgen_t *g, mir_value_t n)
5,549✔
1266
{
1267
   jit_value_t base   = irgen_get_arg(g, n, 0);
5,549✔
1268
   jit_value_t value  = irgen_get_arg(g, n, 1);
5,549✔
1269
   jit_value_t length = irgen_get_arg(g, n, 2);
5,549✔
1270

1271
   mir_type_t type = mir_get_type(g->mu, n);
5,549✔
1272

1273
   jit_value_t addr = jit_addr_from_value(base, 0);
5,549✔
1274
   jit_value_t scale = jit_value_from_int64(irgen_size_bytes(g, type));
5,549✔
1275
   jit_value_t bytes = j_mul(g, length, scale);
5,549✔
1276

1277
   jit_reg_t bytes_r = jit_value_as_reg(bytes);
5,549✔
1278

1279
   if (value.kind == JIT_VALUE_INT64 && value.int64 == 0)
5,549✔
1280
      macro_bzero(g, addr, bytes_r);
3,876✔
1281
   else if (value.kind == JIT_VALUE_DOUBLE) {
1,673✔
1282
      jit_value_t bits = jit_value_from_int64(value.int64);
214✔
1283
      macro_memset(g, irgen_jit_size(g, type), addr, bits, bytes_r);
214✔
1284
   }
1285
   else
1286
      macro_memset(g, irgen_jit_size(g, type), addr, value, bytes_r);
1,459✔
1287
}
5,549✔
1288

1289
static void irgen_send_args(jit_irgen_t *g, mir_value_t n, int first)
65,278✔
1290
{
1291
   const int nargs = mir_count_args(g->mu, n);
65,278✔
1292

1293
   jit_value_t spill = { .kind = JIT_VALUE_INVALID };
65,278✔
1294
   int32_t spilloff = 0;
65,278✔
1295

1296
   for (int i = 0, pslot = first; i < nargs; i++) {
239,376✔
1297
      mir_value_t arg = mir_get_arg(g->mu, n, i);
174,098✔
1298
      if (arg.tag == MIR_TAG_LINKAGE || arg.tag == MIR_TAG_BLOCK)
174,098✔
1299
         continue;   // Skip function name and resume block
38,345✔
1300

1301
      int slots = irgen_slots_for_type(g, mir_get_type(g->mu, arg));
135,753✔
1302

1303
      if (pslot + slots >= JIT_MAX_ARGS - 1) {
135,753✔
1304
         // Large number of arguments spill to the heap
1305
         if (spill.kind == JIT_VALUE_INVALID) {
18✔
1306
            size_t size = slots * sizeof(jit_scalar_t);
3✔
1307
            for (int j = i + 1; j < nargs; j++) {
18✔
1308
               mir_type_t type = mir_get_type(g->mu, mir_get_arg(g->mu, n, j));
15✔
1309
               size += irgen_slots_for_type(g, type) * sizeof(jit_scalar_t);
15✔
1310
            }
1311

1312
            spill = macro_lalloc(g, jit_value_from_int64(size));
3✔
1313
            j_send(g, JIT_MAX_ARGS - 1, spill);
3✔
1314
            pslot = JIT_MAX_ARGS;
3✔
1315
            g->used_tlab = true;
3✔
1316
         }
1317

1318
         jit_reg_t base = irgen_as_reg(g, irgen_get_value(g, arg));
18✔
1319
         for (int j = 0; j < slots; j++, spilloff += sizeof(jit_scalar_t)) {
93✔
1320
            jit_value_t ptr = jit_addr_from_value(spill, spilloff);
75✔
1321
            j_store(g, JIT_SZ_64, jit_value_from_reg(base + j), ptr);
75✔
1322
         }
1323
      }
1324
      else if (slots > 1) {
135,735✔
1325
         jit_reg_t base = jit_value_as_reg(irgen_get_value(g, arg));
41,433✔
1326
         for (int j = 0; j < slots; j++)
165,849✔
1327
            j_send(g, pslot++, jit_value_from_reg(base + j));
124,416✔
1328
      }
1329
      else
1330
         j_send(g, pslot++, irgen_get_value(g, arg));
94,302✔
1331
   }
1332
}
65,278✔
1333

1334
static void irgen_op_return(jit_irgen_t *g, mir_value_t n)
51,222✔
1335
{
1336
   switch (mir_get_kind(g->mu)) {
51,222✔
1337
   case MIR_UNIT_PROCESS:
10,329✔
1338
      if (g->statereg.kind != JIT_VALUE_INVALID) {
10,329✔
1339
         // Set up for first call to process after reset
1340
         jit_value_t ptr = irgen_state_ptr(g);
3,664✔
1341
         j_store(g, JIT_SZ_32, jit_value_from_int64(1), ptr);
3,664✔
1342
         j_send(g, 0, g->statereg);
3,664✔
1343
      }
1344
      else
1345
         j_send(g, 0, jit_null_ptr());   // Stateless process
6,665✔
1346
      break;
1347

1348
   case MIR_UNIT_PROCEDURE:
309✔
1349
      j_send(g, 0, jit_null_ptr());
309✔
1350
      macro_trim(g);
309✔
1351
      break;
309✔
1352

1353
   case MIR_UNIT_INSTANCE:
11,271✔
1354
   case MIR_UNIT_PROTECTED:
1355
   case MIR_UNIT_PACKAGE:
1356
      j_send(g, 0, g->statereg);
11,271✔
1357
      break;
11,271✔
1358

1359
   case MIR_UNIT_PROPERTY:
1,005✔
1360
      if (mir_count_args(g->mu, n) > 0)
1,005✔
1361
         irgen_send_args(g, n, 1);
210✔
1362

1363
      if (g->statereg.kind != JIT_VALUE_INVALID)
1,005✔
1364
         j_send(g, 0, g->statereg);
81✔
1365
      else
1366
         j_send(g, 0, jit_null_ptr());   // Stateless property
924✔
1367
      break;
1368

1369
   case MIR_UNIT_FUNCTION:
28,230✔
1370
   case MIR_UNIT_THUNK:
1371
      if (mir_count_args(g->mu, n) > 0)
28,230✔
1372
         irgen_send_args(g, n, 0);
26,786✔
1373
      else
1374
         j_send(g, 0, jit_null_ptr());  // Procedure compiled as function
1,444✔
1375

1376
      if (g->used_tlab) {
28,230✔
1377
         const mir_mem_t mem = mir_get_mem(g->mu, mir_get_arg(g->mu, n, 0));
7,782✔
1378
         if (mem <= MIR_MEM_CONST)
7,782✔
1379
            macro_trim(g);
2,738✔
1380
         else if (mem == MIR_MEM_STACK) {
5,044✔
NEW
1381
            mir_dump(g->mu);
×
1382
            fatal_trace("returning pointer to stack allocation");
1383
         }
1384
      }
1385
      break;
1386

1387
   case MIR_UNIT_PLACEHOLDER:
1388
      break;
1389
   }
1390

1391
   j_ret(g);
51,222✔
1392
}
51,222✔
1393

1394
static void irgen_op_not(jit_irgen_t *g, mir_value_t n)
2,646✔
1395
{
1396
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
2,646✔
1397
   g->map[n.id] = j_not(g, arg0);
2,646✔
1398
}
2,646✔
1399

1400
static void irgen_op_and(jit_irgen_t *g, mir_value_t n)
4,412✔
1401
{
1402
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
4,412✔
1403
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
4,412✔
1404

1405
   g->map[n.id] = j_and(g, arg0, arg1);
4,412✔
1406
}
4,412✔
1407

1408
static void irgen_op_nand(jit_irgen_t *g, mir_value_t n)
62✔
1409
{
1410
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
62✔
1411
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
62✔
1412

1413
   jit_value_t and = j_and(g, arg0, arg1);
62✔
1414
   g->map[n.id] = j_not(g, and);
62✔
1415
}
62✔
1416

1417
static void irgen_op_or(jit_irgen_t *g, mir_value_t n)
1,788✔
1418
{
1419
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
1,788✔
1420
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
1,788✔
1421

1422
   g->map[n.id] = j_or(g, arg0, arg1);
1,788✔
1423
}
1,788✔
1424

1425
static void irgen_op_nor(jit_irgen_t *g, mir_value_t n)
62✔
1426
{
1427
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
62✔
1428
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
62✔
1429

1430
   jit_value_t or = j_or(g, arg0, arg1);
62✔
1431
   g->map[n.id] = j_not(g, or);
62✔
1432
}
62✔
1433

1434
static void irgen_op_xor(jit_irgen_t *g, mir_value_t n)
104✔
1435
{
1436
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
104✔
1437
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
104✔
1438

1439
   g->map[n.id] = j_xor(g, arg0, arg1);
104✔
1440
}
104✔
1441

1442
static void irgen_op_xnor(jit_irgen_t *g, mir_value_t n)
64✔
1443
{
1444
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
64✔
1445
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
64✔
1446

1447
   jit_value_t xor = j_xor(g, arg0, arg1);
64✔
1448
   g->map[n.id] = j_not(g, xor);
64✔
1449
}
64✔
1450

1451
static void irgen_op_trap_add(jit_irgen_t *g, mir_value_t n)
1,913✔
1452
{
1453
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
1,913✔
1454
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
1,913✔
1455
   jit_value_t locus = irgen_get_arg(g, n, 2);
1,913✔
1456

1457
   mir_type_t type = mir_get_type(g->mu, n);
1,913✔
1458
   jit_size_t sz = irgen_jit_size(g, type);
1,913✔
1459
   mir_repr_t repr = mir_get_repr(g->mu, type);
1,913✔
1460

1461
   jit_cc_t cc = irgen_repr_signed(repr) ? JIT_CC_O : JIT_CC_C;
1,913✔
1462
   g->map[n.id] = j_adds(g, sz, cc, arg0, arg1);
1,913✔
1463

1464
   irgen_label_t *l_pass = irgen_alloc_label(g);
1,913✔
1465
   j_jump(g, JIT_CC_F, l_pass);
1,913✔
1466

1467
   j_send(g, 0, arg0);
1,913✔
1468
   j_send(g, 1, arg1);
1,913✔
1469
   j_send(g, 2, locus);
1,913✔
1470
   macro_exit(g, JIT_EXIT_OVERFLOW);
1,913✔
1471

1472
   irgen_bind_label(g, l_pass);
1,913✔
1473
}
1,913✔
1474

1475
static void irgen_op_add(jit_irgen_t *g, mir_value_t n)
12,928✔
1476
{
1477
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
12,928✔
1478
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
12,928✔
1479

1480
   if (mir_is(g->mu, n, MIR_TYPE_REAL))
12,928✔
1481
      g->map[n.id] = j_fadd(g, arg0, arg1);
266✔
1482
   else
1483
      g->map[n.id] = j_add(g, arg0, arg1);
12,662✔
1484
}
12,928✔
1485

1486
static void irgen_op_trap_mul(jit_irgen_t *g, mir_value_t n)
325✔
1487
{
1488
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
325✔
1489
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
325✔
1490
   jit_value_t locus = irgen_get_arg(g, n, 2);
325✔
1491

1492
   mir_type_t type = mir_get_type(g->mu, n);
325✔
1493
   jit_size_t sz = irgen_jit_size(g, type);
325✔
1494
   mir_repr_t repr = mir_get_repr(g->mu, type);
325✔
1495

1496
   jit_cc_t cc = irgen_repr_signed(repr) ? JIT_CC_O : JIT_CC_C;
325✔
1497
   g->map[n.id] = j_muls(g, sz, cc, arg0, arg1);
325✔
1498

1499
   irgen_label_t *l_pass = irgen_alloc_label(g);
325✔
1500
   j_jump(g, JIT_CC_F, l_pass);
325✔
1501

1502
   j_send(g, 0, arg0);
325✔
1503
   j_send(g, 1, arg1);
325✔
1504
   j_send(g, 2, locus);
325✔
1505
   macro_exit(g, JIT_EXIT_OVERFLOW);
325✔
1506

1507
   irgen_bind_label(g, l_pass);
325✔
1508
}
325✔
1509

1510
static void irgen_op_mul(jit_irgen_t *g, mir_value_t n)
2,091✔
1511
{
1512
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
2,091✔
1513
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
2,091✔
1514

1515
   if (mir_is(g->mu, n, MIR_TYPE_REAL))
2,091✔
1516
      g->map[n.id] = j_fmul(g, arg0, arg1);
548✔
1517
   else
1518
      g->map[n.id] = j_mul(g, arg0, arg1);
1,543✔
1519
}
2,091✔
1520

1521
static void irgen_op_div(jit_irgen_t *g, mir_value_t n)
885✔
1522
{
1523
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
885✔
1524
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
885✔
1525

1526
   if (mir_is(g->mu, n, MIR_TYPE_REAL))
885✔
1527
      g->map[n.id] = j_fdiv(g, arg0, arg1);
216✔
1528
   else
1529
      g->map[n.id] = j_div(g, arg0, arg1);
669✔
1530
}
885✔
1531

1532
static void irgen_op_exp(jit_irgen_t *g, mir_value_t n)
72✔
1533
{
1534
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
72✔
1535
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
72✔
1536

1537
   if (mir_is(g->mu, n, MIR_TYPE_REAL))
72✔
1538
      g->map[n.id] = macro_fexp(g, arg0, arg1);
72✔
1539
   else
UNCOV
1540
      g->map[n.id] = macro_exp(g, JIT_SZ_UNSPEC, JIT_CC_NONE, arg0, arg1);
×
1541
}
72✔
1542

1543
static void irgen_op_trap_exp(jit_irgen_t *g, mir_value_t n)
531✔
1544
{
1545
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
531✔
1546
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
531✔
1547
   jit_value_t locus = irgen_get_arg(g, n, 2);
531✔
1548

1549
   mir_type_t type = mir_get_type(g->mu, n);
531✔
1550
   jit_size_t sz = irgen_jit_size(g, type);
531✔
1551
   mir_repr_t repr = mir_get_repr(g->mu, type);
531✔
1552

1553
   jit_cc_t cc = irgen_repr_signed(repr) ? JIT_CC_O : JIT_CC_C;
531✔
1554
   g->map[n.id] = macro_exp(g, sz, cc, arg0, arg1);
531✔
1555

1556
   irgen_label_t *l_pass = irgen_alloc_label(g);
531✔
1557
   j_jump(g, JIT_CC_F, l_pass);
531✔
1558

1559
   j_send(g, 0, arg0);
531✔
1560
   j_send(g, 1, arg1);
531✔
1561
   j_send(g, 2, locus);
531✔
1562
   macro_exit(g, JIT_EXIT_OVERFLOW);
531✔
1563

1564
   irgen_bind_label(g, l_pass);
531✔
1565
}
531✔
1566

1567
static void irgen_op_sub(jit_irgen_t *g, mir_value_t n)
17,591✔
1568
{
1569
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
17,591✔
1570
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
17,591✔
1571

1572
   if (mir_is(g->mu, n, MIR_TYPE_REAL))
17,591✔
1573
      g->map[n.id] = j_fsub(g, arg0, arg1);
286✔
1574
   else
1575
      g->map[n.id] = j_sub(g, arg0, arg1);
17,305✔
1576
}
17,591✔
1577

1578
static void irgen_op_trap_sub(jit_irgen_t *g, mir_value_t n)
2,039✔
1579
{
1580
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
2,039✔
1581
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
2,039✔
1582
   jit_value_t locus = irgen_get_arg(g, n, 2);
2,039✔
1583

1584
   mir_type_t type = mir_get_type(g->mu, n);
2,039✔
1585
   jit_size_t sz = irgen_jit_size(g, type);
2,039✔
1586
   mir_repr_t repr = mir_get_repr(g->mu, type);
2,039✔
1587

1588
   jit_cc_t cc = irgen_repr_signed(repr) ? JIT_CC_O : JIT_CC_C;
2,039✔
1589
   g->map[n.id] = j_subs(g, sz, cc, arg0, arg1);
2,039✔
1590

1591
   irgen_label_t *l_pass = irgen_alloc_label(g);
2,039✔
1592
   j_jump(g, JIT_CC_F, l_pass);
2,039✔
1593

1594
   j_send(g, 0, arg0);
2,039✔
1595
   j_send(g, 1, arg1);
2,039✔
1596
   j_send(g, 2, locus);
2,039✔
1597
   macro_exit(g, JIT_EXIT_OVERFLOW);
2,039✔
1598

1599
   irgen_bind_label(g, l_pass);
2,039✔
1600
}
2,039✔
1601

1602
static void irgen_op_neg(jit_irgen_t *g, mir_value_t n)
7,480✔
1603
{
1604
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
7,480✔
1605

1606
   if (mir_is_integral(g->mu, n))
7,480✔
1607
      g->map[n.id] = j_neg(g, arg0);
1,539✔
1608
   else
1609
      g->map[n.id] = j_fneg(g, arg0);
5,941✔
1610
}
7,480✔
1611

1612
static void irgen_op_trap_neg(jit_irgen_t *g, mir_value_t n)
555✔
1613
{
1614
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
555✔
1615
   jit_value_t locus = irgen_get_arg(g, n, 1);
555✔
1616

1617
   int64_t cmp;
555✔
1618
   switch (irgen_jit_size(g, mir_get_type(g->mu, n))) {
555✔
1619
   case JIT_SZ_8: cmp = INT8_MIN; break;
1620
   case JIT_SZ_16: cmp = INT16_MIN; break;
1621
   case JIT_SZ_32: cmp = INT32_MIN; break;
1622
   case JIT_SZ_64: cmp = INT64_MIN; break;
1623
   default: cmp = 0;
1624
   }
1625

1626
   irgen_label_t *cont = irgen_alloc_label(g);
555✔
1627
   j_cmp(g, JIT_CC_GT, arg0, jit_value_from_int64(cmp));
555✔
1628
   j_jump(g, JIT_CC_T, cont);
555✔
1629

1630
   j_send(g, 0, arg0);
555✔
1631
   j_send(g, 1, jit_value_from_int64(0));
555✔
1632
   j_send(g, 2, locus);
555✔
1633
   macro_exit(g, JIT_EXIT_OVERFLOW);
555✔
1634

1635
   irgen_bind_label(g, cont);
555✔
1636
   g->map[n.id] = j_neg(g, arg0);
555✔
1637
}
555✔
1638

1639
static void irgen_op_abs(jit_irgen_t *g, mir_value_t n)
233✔
1640
{
1641
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
233✔
1642

1643
   if (mir_is(g->mu, n, MIR_TYPE_REAL)) {
233✔
1644
      jit_value_t neg = j_fneg(g, arg0);
203✔
1645
      j_fcmp(g, JIT_CC_LT, arg0, jit_value_from_double(0.0));
203✔
1646
      g->map[n.id] = j_csel(g, neg, arg0);
203✔
1647
   }
1648
   else {
1649
      jit_value_t neg = j_neg(g, arg0);
30✔
1650
      j_cmp(g, JIT_CC_LT, arg0, jit_value_from_int64(0));
30✔
1651
      g->map[n.id] = j_csel(g, neg, arg0);
30✔
1652
   }
1653
}
233✔
1654

1655
static void irgen_op_mod(jit_irgen_t *g, mir_value_t n)
151✔
1656
{
1657
   jit_value_t numer = irgen_get_arg(g, n, 0);
151✔
1658
   jit_value_t denom = irgen_get_arg(g, n, 1);
151✔
1659

1660
   // Calculate the following:
1661
   //
1662
   //   long r = numer % denom;
1663
   //   if ((r > 0 && denom < 0) || (r < 0 && denom > 0))
1664
   //      r = r + denom;
1665

1666
   jit_value_t r = j_rem(g, numer, denom);
151✔
1667

1668
   irgen_label_t *l1 = irgen_alloc_label(g);
151✔
1669
   irgen_label_t *l2 = irgen_alloc_label(g);
151✔
1670

1671
   jit_value_t zero = jit_value_from_int64(0);
151✔
1672

1673
   j_cmp(g, JIT_CC_GT, r, zero);
151✔
1674
   j_ccmp(g, JIT_CC_LT, denom, zero);
151✔
1675
   j_jump(g, JIT_CC_T, l1);
151✔
1676

1677
   j_cmp(g, JIT_CC_LT, r, zero);
151✔
1678
   j_ccmp(g, JIT_CC_GT, denom, zero);
151✔
1679
   j_jump(g, JIT_CC_F, l2);
151✔
1680

1681
   irgen_bind_label(g, l1);
151✔
1682

1683
   jit_value_t r2 = j_add(g, r, denom);
151✔
1684
   j_mov(g, jit_value_as_reg(r), r2);
151✔
1685

1686
   irgen_bind_label(g, l2);
151✔
1687

1688
   g->map[n.id] = r;
151✔
1689
}
151✔
1690

1691
static void irgen_op_rem(jit_irgen_t *g, mir_value_t n)
94✔
1692
{
1693
   jit_value_t arg0 = irgen_get_arg(g, n, 0);
94✔
1694
   jit_value_t arg1 = irgen_get_arg(g, n, 1);
94✔
1695

1696
   g->map[n.id] = j_rem(g, arg0, arg1);
94✔
1697
}
94✔
1698

1699
static void irgen_op_cmp(jit_irgen_t *g, mir_value_t n)
33,541✔
1700
{
1701
   mir_value_t arg1 = mir_get_arg(g->mu, n, 1);
33,541✔
1702
   jit_value_t left = irgen_get_value(g, arg1);
33,541✔
1703
   jit_value_t right = irgen_get_arg(g, n, 2);
33,541✔
1704

1705
   jit_cc_t cc = irgen_get_jit_cc(irgen_get_enum(g, n, 0));
33,541✔
1706

1707
   if (mir_is(g->mu, arg1, MIR_TYPE_REAL))
33,541✔
1708
      j_fcmp(g, cc, left, right);
1,694✔
1709
   else
1710
      j_cmp(g, cc, left, right);
31,847✔
1711

1712
   g->map[n.id] = j_cset(g);
33,541✔
1713
   g->flags = n;
33,541✔
1714
}
33,541✔
1715

1716
static jit_value_t irgen_load_addr(jit_irgen_t *g, mir_type_t type,
117,060✔
1717
                                   jit_value_t ptr)
1718
{
1719
   jit_value_t addr = jit_addr_from_value(ptr, 0);
117,060✔
1720

1721
   switch (mir_get_class(g->mu, type)) {
117,060✔
1722
   case MIR_TYPE_OFFSET:
42,591✔
1723
   case MIR_TYPE_INT:
1724
      if (irgen_repr_signed(mir_get_repr(g->mu, type)))
42,591✔
1725
         return j_load(g, irgen_jit_size(g, type), addr);
23,840✔
1726
      else
1727
         return j_uload(g, irgen_jit_size(g, type), addr);
18,751✔
1728

1729
   case MIR_TYPE_REAL:
3,888✔
1730
      return j_load(g, JIT_SZ_64, addr);
3,888✔
1731

1732
   case MIR_TYPE_ACCESS:
3,008✔
1733
   case MIR_TYPE_POINTER:
1734
   case MIR_TYPE_CONTEXT:
1735
   case MIR_TYPE_FILE:
1736
   case MIR_TYPE_TRIGGER:
1737
      return j_load(g, JIT_SZ_PTR, addr);
3,008✔
1738

1739
   case MIR_TYPE_SIGNAL:
50,023✔
1740
      {
1741
         jit_value_t shared = j_load(g, JIT_SZ_PTR, addr);
50,023✔
1742
         addr = jit_addr_from_value(addr, sizeof(void *));
50,023✔
1743
         j_load(g, JIT_SZ_32, addr);   // Offset
50,023✔
1744
         return shared;
50,023✔
1745
      }
1746

1747
   case MIR_TYPE_UARRAY:
17,550✔
1748
      {
1749
         const int slots = irgen_slots_for_type(g, mir_get_elem(g->mu, type));
17,550✔
1750
         jit_value_t base = j_load(g, JIT_SZ_PTR, addr);
17,550✔
1751
         addr = jit_addr_from_value(addr, sizeof(void *));
17,550✔
1752
         for (int i = 1; i < slots; i++) {
20,119✔
1753
            j_load(g, JIT_SZ_PTR, addr);
2,569✔
1754
            addr = jit_addr_from_value(addr, sizeof(void *));
2,569✔
1755
         }
1756

1757
         const int ndims = mir_get_dims(g->mu, type);
17,550✔
1758
         for (int i = 0; i < 2*ndims; i++) {
53,286✔
1759
            j_load(g, JIT_SZ_64, addr);
35,736✔
1760
            addr = jit_addr_from_value(addr, sizeof(int64_t));
35,736✔
1761
         }
1762

1763
         return base;
17,550✔
1764
      }
1765

UNCOV
1766
   default:
×
1767
      fatal_trace("cannot load type kind %d", mir_get_class(g->mu, type));
1768
   }
1769
}
1770

1771
static void irgen_op_load(jit_irgen_t *g, mir_value_t n)
117,060✔
1772
{
1773
   jit_value_t addr = irgen_get_arg(g, n, 0);
117,060✔
1774
   mir_type_t type = mir_get_type(g->mu, n);
117,060✔
1775

1776
   g->map[n.id] = irgen_load_addr(g, type, addr);
117,060✔
1777
}
117,060✔
1778

1779
static void irgen_store_addr(jit_irgen_t *g, mir_type_t type,
71,915✔
1780
                             jit_value_t value, jit_value_t ptr)
1781
{
1782
   jit_value_t addr = jit_addr_from_value(ptr, 0);
71,915✔
1783

1784
   if (jit_value_is_addr(value))
71,915✔
1785
      value = irgen_lea(g, value);   // Storing an address
1,176✔
1786

1787
   switch (mir_get_class(g->mu, type)) {
71,915✔
1788
   case MIR_TYPE_OFFSET:
44,259✔
1789
   case MIR_TYPE_INT:
1790
   case MIR_TYPE_ACCESS:
1791
   case MIR_TYPE_POINTER:
1792
   case MIR_TYPE_CONTEXT:
1793
   case MIR_TYPE_REAL:
1794
   case MIR_TYPE_FILE:
1795
   case MIR_TYPE_TRIGGER:
1796
      j_store(g, irgen_jit_size(g, type), value, addr);
44,259✔
1797
      break;
44,259✔
1798

1799
   case MIR_TYPE_UARRAY:
8,160✔
1800
      {
1801
         const int slots = irgen_slots_for_type(g, mir_get_elem(g->mu, type));
8,160✔
1802
         jit_reg_t base = jit_value_as_reg(value);
8,160✔
1803
         for (int i = 0; i < slots; i++) {
17,619✔
1804
            j_store(g, JIT_SZ_PTR, jit_value_from_reg(base + i), addr);
9,459✔
1805
            addr = jit_addr_from_value(addr, sizeof(void *));
9,459✔
1806
         }
1807

1808
         const int ndims = mir_get_dims(g->mu, type);
8,160✔
1809
         for (int i = 0; i < 2*ndims; i++) {
24,900✔
1810
            j_store(g, JIT_SZ_64, jit_value_from_reg(base + slots + i), addr);
16,740✔
1811
            addr = jit_addr_from_value(addr, sizeof(int64_t));
16,740✔
1812
         }
1813
      }
1814
      break;
1815

1816
   case MIR_TYPE_SIGNAL:
19,496✔
1817
      {
1818
         jit_reg_t base = jit_value_as_reg(value);
19,496✔
1819
         j_store(g, JIT_SZ_PTR, value, addr);
19,496✔
1820
         addr = jit_addr_from_value(addr, sizeof(void *));
19,496✔
1821
         j_store(g, JIT_SZ_32, jit_value_from_reg(base + 1), addr);
19,496✔
1822
      }
1823
      break;
19,496✔
1824

UNCOV
1825
   default:
×
1826
      fatal_trace("cannot store type kind %d", mir_get_class(g->mu, type));
1827
   }
1828
}
71,915✔
1829

1830
static void irgen_op_store(jit_irgen_t *g, mir_value_t n)
71,915✔
1831
{
1832
   jit_value_t addr = irgen_get_arg(g, n, 0);
71,915✔
1833
   jit_value_t value = irgen_get_arg(g, n, 1);
71,915✔
1834
   mir_type_t type = mir_get_type(g->mu, n);
71,915✔
1835

1836
   irgen_store_addr(g, type, value, addr);
71,915✔
1837
}
71,915✔
1838

1839
static void irgen_op_locus(jit_irgen_t *g, mir_value_t n)
65,860✔
1840
{
1841
   g->map[n.id] = (jit_value_t){
131,720✔
1842
      .kind  = JIT_VALUE_LOCUS,
1843
      .locus = mir_get_locus(g->mu, n),
65,860✔
1844
   };
1845
}
65,860✔
1846

1847
static void irgen_op_wrap(jit_irgen_t *g, mir_value_t n)
28,989✔
1848
{
28,989✔
1849
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
28,989✔
1850
   jit_value_t ptr = irgen_lea(g, irgen_get_value(g, arg0));
28,989✔
1851

1852
   mir_type_t type = mir_get_type(g->mu, arg0);
28,989✔
1853

1854
   const int ndims = mir_count_args(g->mu, n) / 3;
28,989✔
1855
   const int slots = irgen_slots_for_type(g, type);
28,989✔
1856

1857
   // Registers must be contiguous
1858
   jit_reg_t base = irgen_alloc_reg(g);
28,989✔
1859
   j_mov(g, base, ptr);
28,989✔
1860
   for (int i = 1; i < slots; i++) {
30,239✔
1861
      jit_reg_t slot = irgen_alloc_reg(g);
1,250✔
1862
      j_mov(g, slot, jit_value_from_reg(jit_value_as_reg(ptr) + i));
1,250✔
1863
   }
1864
   jit_reg_t dims[ndims * 2];
28,989✔
1865
   for (int i = 0; i < ndims * 2; i++)
87,789✔
1866
      dims[i] = irgen_alloc_reg(g);
58,800✔
1867

1868
   for (int i = 0; i < ndims; i++) {
58,389✔
1869
      jit_value_t left  = irgen_get_arg(g, n, (i * 3) + 1);
29,400✔
1870
      jit_value_t right = irgen_get_arg(g, n, (i * 3) + 2);
29,400✔
1871
      jit_value_t dir   = irgen_get_arg(g, n, (i * 3) + 3);
29,400✔
1872

1873
      jit_value_t diff_up   = j_sub(g, right, left);
29,400✔
1874
      jit_value_t diff_down = j_sub(g, left, right);
29,400✔
1875

1876
      j_cmp(g, JIT_CC_EQ, dir, jit_value_from_int64(RANGE_DOWNTO));
29,400✔
1877
      jit_value_t diff    = j_csel(g, diff_down, diff_up);
29,400✔
1878
      jit_value_t length  = j_add(g, diff, jit_value_from_int64(1));
29,400✔
1879
      jit_value_t clamped = j_clamp(g, length);
29,400✔
1880
      jit_value_t mask    = j_neg(g, dir);
29,400✔
1881
      jit_value_t signlen = j_xor(g, mask, clamped);
29,400✔
1882

1883
      j_mov(g, dims[i*2], left);
29,400✔
1884
      j_mov(g, dims[i*2 + 1], signlen);
29,400✔
1885
   }
1886

1887
   g->map[n.id] = jit_value_from_reg(base);
28,989✔
1888
}
28,989✔
1889

1890
static void irgen_op_uarray_right(jit_irgen_t *g, mir_value_t n)
14,520✔
1891
{
1892
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
14,520✔
1893
   jit_reg_t base = jit_value_as_reg(irgen_get_value(g, arg0));
14,520✔
1894

1895
   mir_type_t elem = mir_get_elem(g->mu, mir_get_type(g->mu, arg0));
14,520✔
1896

1897
   const int dim = irgen_get_const(g, n, 1);
14,520✔
1898
   const int slots = irgen_slots_for_type(g, elem);
14,520✔
1899

1900
   jit_value_t left   = jit_value_from_reg(base + slots + dim*2);
14,520✔
1901
   jit_value_t length = jit_value_from_reg(base + slots + 1 + dim*2);
14,520✔
1902
   jit_value_t diff   = j_add(g, left, length);
14,520✔
1903
   j_cmp(g, JIT_CC_LT, length, jit_value_from_int64(0));
14,520✔
1904

1905
   jit_value_t adj = j_csel(g, jit_value_from_int64(2),
14,520✔
1906
                            jit_value_from_int64(-1));
1907

1908
   g->map[n.id] = j_add(g, diff, adj);
14,520✔
1909
}
14,520✔
1910

1911
static void irgen_op_uarray_left(jit_irgen_t *g, mir_value_t n)
16,600✔
1912
{
1913
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
16,600✔
1914
   jit_reg_t base = jit_value_as_reg(irgen_get_value(g, arg0));
16,600✔
1915

1916
   mir_type_t elem = mir_get_elem(g->mu, mir_get_type(g->mu, arg0));
16,600✔
1917

1918
   const int dim = irgen_get_const(g, n, 1);
16,600✔
1919
   const int slots = irgen_slots_for_type(g, elem);
16,600✔
1920

1921
   g->map[n.id] = jit_value_from_reg(base + slots + dim*2);
16,600✔
1922
}
16,600✔
1923

1924
static void irgen_op_uarray_dir(jit_irgen_t *g, mir_value_t n)
16,562✔
1925
{
1926
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
16,562✔
1927
   jit_reg_t base = jit_value_as_reg(irgen_get_value(g, arg0));
16,562✔
1928

1929
   mir_type_t elem = mir_get_elem(g->mu, mir_get_type(g->mu, arg0));
16,562✔
1930

1931
   const int dim = irgen_get_const(g, n, 1);
16,562✔
1932
   const int slots = irgen_slots_for_type(g, elem);
16,562✔
1933

1934
   jit_value_t length = jit_value_from_reg(base + slots + 1 + dim*2);
16,562✔
1935
   j_cmp(g, JIT_CC_LT, length, jit_value_from_int64(0));
16,562✔
1936

1937
   STATIC_ASSERT(RANGE_DOWNTO == 1);
16,562✔
1938

1939
   g->map[n.id] = j_cset(g);
16,562✔
1940
   g->flags = n;
16,562✔
1941
}
16,562✔
1942

1943
static void irgen_op_uarray_len(jit_irgen_t *g, mir_value_t n)
20,668✔
1944
{
1945
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
20,668✔
1946
   jit_reg_t base = jit_value_as_reg(irgen_get_value(g, arg0));
20,668✔
1947

1948
   mir_type_t elem = mir_get_elem(g->mu, mir_get_type(g->mu, arg0));
20,668✔
1949

1950
   const int dim = irgen_get_const(g, n, 1);
20,668✔
1951
   const int slots = irgen_slots_for_type(g, elem);
20,668✔
1952

1953
   jit_value_t length = jit_value_from_reg(base + slots + 1 + dim*2);
20,668✔
1954
   jit_value_t mask = j_asr(g, length, jit_value_from_int64(63));
20,668✔
1955
   g->map[n.id] = j_xor(g, mask, length);
20,668✔
1956
}
20,668✔
1957

1958
static void irgen_op_unwrap(jit_irgen_t *g, mir_value_t n)
24,249✔
1959
{
1960
   jit_value_t base = irgen_get_arg(g, n, 0);
24,249✔
1961
   g->map[n.id] = base;
24,249✔
1962
}
24,249✔
1963

1964
static void irgen_op_array_ref(jit_irgen_t *g, mir_value_t n)
32,376✔
1965
{
1966
   if (mir_is_signal(g->mu, n)) {
32,376✔
1967
      jit_value_t shared = irgen_get_arg(g, n, 0);
6,987✔
1968
      jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
6,987✔
1969

1970
      jit_value_t arg1 = irgen_get_arg(g, n, 1);
6,987✔
1971

1972
      if (arg1.kind == JIT_VALUE_INT64 && arg1.int64 == 0)
6,987✔
1973
         g->map[n.id] = shared;
1,622✔
1974
      else {
1975
         jit_reg_t new = irgen_alloc_reg(g);
5,365✔
1976
         j_mov(g, new, shared);
5,365✔
1977
         g->map[n.id] = jit_value_from_reg(new);
5,365✔
1978

1979
         // Offset must be next sequential register
1980
         j_add(g, offset, arg1);
5,365✔
1981
      }
1982
   }
1983
   else {
1984
      assert(mir_is(g->mu, n, MIR_TYPE_POINTER));
25,389✔
1985
      mir_type_t elem = mir_get_elem(g->mu, mir_get_type(g->mu, n));
25,389✔
1986
      const int scale = irgen_size_bytes(g, elem);
25,389✔
1987

1988
      jit_value_t arg0 = irgen_get_arg(g, n, 0);
25,389✔
1989
      jit_value_t arg1 = irgen_get_arg(g, n, 1);
25,389✔
1990

1991
      if (arg1.kind == JIT_VALUE_INT64)
25,389✔
1992
         g->map[n.id] = jit_addr_from_value(arg0, arg1.int64 * scale);
7,353✔
1993
      else {
1994
         jit_value_t scaled = j_mul(g, arg1, jit_value_from_int64(scale));
18,036✔
1995
         jit_value_t addr = irgen_lea(g, arg0);
18,036✔
1996
         g->map[n.id] = j_add(g, addr, scaled);
18,036✔
1997
      }
1998
   }
1999
}
32,376✔
2000

2001
static void irgen_op_record_ref(jit_irgen_t *g, mir_value_t n)
37,502✔
2002
{
2003
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
37,502✔
2004
   mir_type_t rtype = mir_get_elem(g->mu, mir_get_type(g->mu, arg0));
37,502✔
2005
   assert(mir_get_class(g->mu, rtype) == MIR_TYPE_RECORD);
37,502✔
2006

2007
   const int field = irgen_get_const(g, n, 1);
37,502✔
2008

2009
   size_t nfields;
37,502✔
2010
   const mir_type_t *ftypes = mir_get_fields(g->mu, rtype, &nfields);
37,502✔
2011
   assert(field < nfields);
37,502✔
2012

2013
   // TODO: cache field offsets somewhere? This duplicates irgen_size_bytes
2014
   int offset = 0;
2015
   for (int i = 0; i < field; i++) {
120,914✔
2016
      const int fb = irgen_size_bytes(g, ftypes[i]);
83,412✔
2017
      const int align = irgen_align_of(g, ftypes[i]);
83,412✔
2018

2019
      offset = ALIGN_UP(offset, align);
83,412✔
2020
      offset += fb;
83,412✔
2021
   }
2022

2023
   const int align = irgen_align_of(g, ftypes[field]);
37,502✔
2024
   offset = ALIGN_UP(offset, align);
37,502✔
2025

2026
   jit_value_t rptr = irgen_get_value(g, arg0);
37,502✔
2027
   g->map[n.id] = jit_addr_from_value(rptr, offset);
37,502✔
2028
}
37,502✔
2029

2030
static void irgen_op_context_upref(jit_irgen_t *g, mir_value_t n)
8,648✔
2031
{
2032
   const int hops = irgen_get_const(g, n, 0);
8,648✔
2033

2034
   if (hops == 0) {
8,648✔
2035
      assert(g->statereg.kind != JIT_VALUE_INVALID);
987✔
2036
      g->map[n.id] = g->statereg;
987✔
2037
   }
2038
   else {
2039
      jit_value_t context = irgen_get_context(g);
7,661✔
2040

2041
      for (int i = 1; i < hops; i++)
7,931✔
2042
         context = j_load(g, JIT_SZ_PTR, jit_addr_from_value(context, 0));
270✔
2043

2044
      g->map[n.id] = context;
7,661✔
2045
   }
2046
}
8,648✔
2047

2048
static void irgen_op_var_upref(jit_irgen_t *g, mir_value_t n)
45,545✔
2049
{
2050
   jit_value_t context = irgen_get_context(g);
45,545✔
2051

2052
   const int hops = irgen_get_const(g, n, 0);
45,545✔
2053
   const int nth = irgen_get_const(g, n, 2);
45,545✔
2054
   ident_t unit_name = mir_get_name(g->mu, mir_get_arg(g->mu, n, 1));
45,545✔
2055

2056
   for (int i = 1; i < hops; i++)
56,068✔
2057
      context = j_load(g, JIT_SZ_PTR, jit_addr_from_value(context, 0));
10,523✔
2058

2059
   // TODO: maybe we should cache these somewhere?
2060
   jit_handle_t handle = jit_lazy_compile(g->func->jit, unit_name);
45,545✔
2061
   jit_func_t *cf = jit_get_func(g->func->jit, handle);
45,545✔
2062

2063
   // Handle potential circular dependency
2064
   // TODO: it would be better to avoid this entirely
2065
   const link_tab_t *tab = load_acquire(&(cf->linktab));
45,545✔
2066
   if (tab == NULL) {
45,545✔
2067
      jit_fill_irbuf(cf);
79✔
2068
      tab = load_acquire(&(cf->linktab));
79✔
2069
      assert(tab);
79✔
2070
   }
2071

2072
   assert(nth < cf->nvars);
45,545✔
2073
   const int offset = tab[nth].offset;
45,545✔
2074

2075
   g->map[n.id] = jit_addr_from_value(context, offset);
45,545✔
2076
}
45,545✔
2077

2078
static void irgen_op_cast(jit_irgen_t *g, mir_value_t n)
45,752✔
2079
{
2080
   mir_value_t arg = mir_get_arg(g->mu, n, 0);
45,752✔
2081

2082
   mir_type_t result_type = mir_get_type(g->mu, n);
45,752✔
2083
   mir_class_t result_kind = mir_get_class(g->mu, result_type);
45,752✔
2084

2085
   if (result_kind == MIR_TYPE_REAL && mir_is_integral(g->mu, arg))
45,752✔
2086
      g->map[n.id] = j_scvtf(g, irgen_get_value(g, arg));
253✔
2087
   else if (result_kind == MIR_TYPE_INT && mir_is(g->mu, arg, MIR_TYPE_REAL))
45,499✔
2088
      g->map[n.id] = j_fcvtns(g, irgen_get_value(g, arg));
103✔
2089
   else if (result_kind == MIR_TYPE_INT || result_kind == MIR_TYPE_OFFSET) {
45,396✔
2090
      // No sign extension or truncation is necessary as integer
2091
      // registers are always 64 bits wide
2092
      g->map[n.id] = irgen_get_value(g, arg);
45,107✔
2093
   }
2094
   else if (result_kind == MIR_TYPE_REAL) {
289✔
2095
      // Reals are always represented with IEEE doubles
2096
      assert(mir_is(g->mu, arg, MIR_TYPE_REAL));
×
UNCOV
2097
      g->map[n.id] = irgen_get_value(g, arg);
×
2098
   }
2099
   else if (result_kind == MIR_TYPE_ACCESS) {
289✔
2100
      // Casting away opaqueness
2101
      assert(mir_is(g->mu, arg, MIR_TYPE_ACCESS));
289✔
2102
      g->map[n.id] = irgen_get_value(g, arg);
289✔
2103
   }
2104
   else {
UNCOV
2105
      mir_dump(g->mu);
×
2106
      fatal_trace("unhandled cast");
2107
   }
2108
}
45,752✔
2109

2110
static void irgen_op_range_null(jit_irgen_t *g, mir_value_t n)
4,610✔
2111
{
2112
   jit_value_t left  = irgen_get_arg(g, n, 0);
4,610✔
2113
   jit_value_t right = irgen_get_arg(g, n, 1);
4,610✔
2114

2115
   irgen_label_t *l_downto = irgen_alloc_label(g);
4,610✔
2116
   irgen_label_t *l_after  = irgen_alloc_label(g);
4,610✔
2117

2118
   mir_value_t arg2 = mir_get_arg(g->mu, n, 2);
4,610✔
2119
   if (!mir_equals(arg2, g->flags)) {
4,610✔
2120
      jit_value_t dir = irgen_get_value(g, arg2);
3,421✔
2121
      j_cmp(g, JIT_CC_EQ, dir, jit_value_from_int64(RANGE_DOWNTO));
3,421✔
2122
   }
2123

2124
   j_jump(g, JIT_CC_T, l_downto);
4,610✔
2125

2126
   j_cmp(g, JIT_CC_GT, left, right);
4,610✔
2127
   j_jump(g, JIT_CC_NONE, l_after);
4,610✔
2128

2129
   irgen_bind_label(g, l_downto);
4,610✔
2130

2131
   j_cmp(g, JIT_CC_GT, right, left);
4,610✔
2132

2133
   irgen_bind_label(g, l_after);
4,610✔
2134

2135
   g->map[n.id] = j_cset(g);
4,610✔
2136
   g->flags = n;
4,610✔
2137
}
4,610✔
2138

2139
static void irgen_op_range_length(jit_irgen_t *g, mir_value_t n)
6,132✔
2140
{
2141
   jit_value_t left  = irgen_get_arg(g, n, 0);
6,132✔
2142
   jit_value_t right = irgen_get_arg(g, n, 1);
6,132✔
2143

2144
   mir_value_t arg2 = mir_get_arg(g->mu, n, 2);
6,132✔
2145

2146
   jit_value_t diff;
6,132✔
2147
   int64_t dconst;
6,132✔
2148
   if (mir_get_const(g->mu, arg2, &dconst)) {
6,132✔
2149
      jit_value_t high = dconst == RANGE_TO ? right : left;
5,356✔
2150
      jit_value_t low = dconst == RANGE_TO ? left : right;
5,356✔
2151

2152
      diff = j_sub(g, high, low);
5,356✔
2153
   }
2154
   else {
2155
      irgen_label_t *l_downto = irgen_alloc_label(g);
776✔
2156
      irgen_label_t *l_after  = irgen_alloc_label(g);
776✔
2157
      if (!mir_equals(arg2, g->flags)) {
776✔
2158
         jit_value_t dir = irgen_get_value(g, arg2);
210✔
2159
         j_cmp(g, JIT_CC_EQ, dir, jit_value_from_int64(RANGE_DOWNTO));
210✔
2160
      }
2161

2162
      j_jump(g, JIT_CC_T, l_downto);
776✔
2163

2164
      jit_value_t diff_up = j_sub(g, right, left);
776✔
2165
      j_jump(g, JIT_CC_NONE, l_after);
776✔
2166

2167
      irgen_bind_label(g, l_downto);
776✔
2168

2169
      jit_value_t diff_down = j_sub(g, left, right);
776✔
2170

2171
      irgen_bind_label(g, l_after);
776✔
2172

2173
      diff = j_csel(g, diff_down, diff_up);
776✔
2174
   }
2175

2176
   jit_value_t length = j_add(g, diff, jit_value_from_int64(1));
6,132✔
2177
   jit_value_t clamped = j_clamp(g, length);
6,132✔
2178

2179
   g->map[n.id] = clamped;
6,132✔
2180
}
6,132✔
2181

2182
static void irgen_op_cond(jit_irgen_t *g, mir_value_t n)
32,928✔
2183
{
2184
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
32,928✔
2185
   if (!mir_equals(arg0, g->flags)) {
32,928✔
2186
      jit_value_t test = irgen_get_value(g, arg0);
8,696✔
2187
      j_cmp(g, JIT_CC_NE, test, jit_value_from_int64(0));
8,696✔
2188
   }
2189

2190
   mir_block_t t0 = mir_cast_block(mir_get_arg(g->mu, n, 1));
32,928✔
2191
   mir_block_t t1 = mir_cast_block(mir_get_arg(g->mu, n, 2));
32,928✔
2192

2193
   if (t0.id == g->curblock.id + 1)
32,928✔
2194
      j_jump(g, JIT_CC_F, g->blocks[t1.id]);
10,926✔
2195
   else if (t1.id == g->curblock.id + 1)
22,002✔
2196
      j_jump(g, JIT_CC_T, g->blocks[t0.id]);
12,977✔
2197
   else {
2198
      j_jump(g, JIT_CC_T, g->blocks[t0.id]);
9,025✔
2199
      j_jump(g, JIT_CC_NONE, g->blocks[t1.id]);
9,025✔
2200
   }
2201
}
32,928✔
2202

2203
static void irgen_op_case(jit_irgen_t *g, mir_value_t n)
621✔
2204
{
2205
   jit_value_t value = irgen_get_arg(g, n, 0);
621✔
2206
   jit_reg_t reg = jit_value_as_reg(value);
621✔
2207
   mir_block_t def = mir_cast_block(mir_get_arg(g->mu, n, 1));
621✔
2208

2209
   const int nargs = mir_count_args(g->mu, n);
621✔
2210
   for (int i = 2; i < nargs; i += 2) {
5,222✔
2211
      jit_value_t cmp = irgen_get_arg(g, n, i);
4,601✔
2212
      mir_block_t b = mir_cast_block(mir_get_arg(g->mu, n, i + 1));
4,601✔
2213
      irgen_label_t *l = g->blocks[b.id];
4,601✔
2214
      macro_case(g, reg, cmp, l);
4,601✔
2215
   }
2216

2217
   j_jump(g, JIT_CC_NONE, g->blocks[def.id]);
621✔
2218
}
621✔
2219

2220
static void irgen_op_select(jit_irgen_t *g, mir_value_t n)
12,307✔
2221
{
2222
   jit_value_t iftrue  = irgen_get_arg(g, n, 1);
12,307✔
2223
   jit_value_t iffalse = irgen_get_arg(g, n, 2);
12,307✔
2224

2225
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
12,307✔
2226
   if (!mir_equals(arg0, g->flags)) {
12,307✔
2227
      jit_value_t test = irgen_get_arg(g, n, 0);
7,130✔
2228
      j_cmp(g, JIT_CC_NE, test, jit_value_from_int64(0));
7,130✔
2229
   }
2230

2231
   g->map[n.id] = j_csel(g, iftrue, iffalse);
12,307✔
2232

2233
   const int slots = irgen_slots_for_type(g, mir_get_type(g->mu, n));
12,307✔
2234
   for (int i = 1; i < slots; i++) {
12,507✔
2235
      jit_value_t iftrue_i = jit_value_from_reg(jit_value_as_reg(iftrue) + i);
200✔
2236
      jit_value_t iffalse_i = jit_value_from_reg(jit_value_as_reg(iffalse) + i);
200✔
2237
      j_csel(g, iftrue_i, iffalse_i);
200✔
2238
   }
2239
}
12,307✔
2240

2241
static void irgen_op_jump(jit_irgen_t *g, mir_value_t n)
35,153✔
2242
{
2243
   mir_block_t target = mir_cast_block(mir_get_arg(g->mu, n, 0));
35,153✔
2244
   j_jump(g, JIT_CC_NONE, g->blocks[target.id]);
35,153✔
2245
}
35,153✔
2246

2247
static void irgen_op_fcall(jit_irgen_t *g, mir_value_t n)
35,798✔
2248
{
2249
   irgen_emit_debuginfo(g, n);   // For stack traces
35,798✔
2250

2251
   mir_type_t rtype = mir_get_type(g->mu, n);
35,798✔
2252
   if (mir_is_null(rtype)) {
35,798✔
2253
      // Must call using procedure calling convention
2254
      j_send(g, 0, jit_value_from_int64(0));
4,960✔
2255
      irgen_send_args(g, n, 1);
4,960✔
2256
   }
2257
   else
2258
      irgen_send_args(g, n, 0);
30,838✔
2259

2260
   j_call(g, irgen_get_handle(g, n, 0));
35,798✔
2261

2262
   if (!mir_is_null(rtype)) {
35,798✔
2263
      const int slots = irgen_slots_for_type(g, rtype);
30,838✔
2264
      g->map[n.id] = j_recv(g, 0);
30,838✔
2265
      for (int i = 1; i < slots; i++)
53,870✔
2266
         j_recv(g, i);   // Must be contiguous registers
23,032✔
2267

2268
      const mir_class_t rclass = mir_get_class(g->mu, rtype);
30,838✔
2269
      g->used_tlab |= rclass == MIR_TYPE_UARRAY
30,838✔
2270
         || rclass == MIR_TYPE_POINTER;
30,838✔
2271
   }
2272
   else {
2273
      irgen_label_t *cont = irgen_alloc_label(g);
4,960✔
2274
      jit_value_t state = j_recv(g, 0);
4,960✔
2275
      j_cmp(g, JIT_CC_EQ, state, jit_null_ptr());
4,960✔
2276
      j_jump(g, JIT_CC_T, cont);
4,960✔
2277
      macro_exit(g, JIT_EXIT_FUNC_WAIT);
4,960✔
2278
      irgen_bind_label(g, cont);
4,960✔
2279
   }
2280
}
35,798✔
2281

2282
static void irgen_op_syscall(jit_irgen_t *g, mir_value_t n)
423✔
2283
{
2284
   irgen_emit_debuginfo(g, n);   // For stack traces
423✔
2285

2286
   irgen_send_args(g, n, 0);
423✔
2287
   macro_exit(g, JIT_EXIT_SYSCALL);
423✔
2288

2289
   mir_type_t rtype = mir_get_type(g->mu, n);
423✔
2290
   if (!mir_is_null(rtype)) {
423✔
2291
      const int slots = irgen_slots_for_type(g, rtype);
39✔
2292
      g->map[n.id] = j_recv(g, 0);
39✔
2293
      for (int i = 1; i < slots; i++)
117✔
2294
         j_recv(g, i);   // Must be contiguous registers
78✔
2295
   }
2296
}
423✔
2297

2298
static void irgen_pcall_suspend(jit_irgen_t *g, jit_value_t state,
1,750✔
2299
                                irgen_label_t *cont)
2300
{
2301
   jit_value_t pcall_ptr = irgen_pcall_ptr(g);
1,750✔
2302
   j_store(g, JIT_SZ_PTR, state, pcall_ptr);
1,750✔
2303

2304
   j_cmp(g, JIT_CC_EQ, state, jit_null_ptr());
1,750✔
2305
   j_jump(g, JIT_CC_T, cont);
1,750✔
2306

2307
   j_send(g, 0, g->statereg);
1,750✔
2308

2309
   j_ret(g);
1,750✔
2310
}
1,750✔
2311

2312
static void irgen_op_pcall(jit_irgen_t *g, mir_value_t n)
875✔
2313
{
2314
   irgen_emit_debuginfo(g, n);   // For stack traces
875✔
2315

2316
   // First argument to procedure is suspended state
2317
   j_send(g, 0, jit_value_from_int64(0));
875✔
2318

2319
   irgen_send_args(g, n, 1);
875✔
2320

2321
   jit_handle_t handle = irgen_get_handle(g, n, 1);
875✔
2322
   j_call(g, handle);
875✔
2323

2324
   irgen_label_t *cont = irgen_alloc_label(g);
875✔
2325
   jit_value_t state = j_recv(g, 0);
875✔
2326

2327
   mir_block_t resume = mir_cast_block(mir_get_arg(g->mu, n, 0));
875✔
2328

2329
   jit_value_t state_ptr = irgen_state_ptr(g);
875✔
2330
   j_store(g, JIT_SZ_32, jit_value_from_int64(resume.id), state_ptr);
875✔
2331

2332
   irgen_pcall_suspend(g, state, cont);
875✔
2333

2334
   irgen_bind_label(g, cont);
875✔
2335
   j_jump(g, JIT_CC_NONE, g->blocks[resume.id]);
875✔
2336
}
875✔
2337

2338
static void irgen_op_resume(jit_irgen_t *g, mir_value_t n)
875✔
2339
{
2340
   jit_value_t old_state = j_load(g, JIT_SZ_PTR, irgen_pcall_ptr(g));
875✔
2341
   irgen_label_t *cont = irgen_alloc_label(g);
875✔
2342
   j_cmp(g, JIT_CC_EQ, old_state, jit_null_ptr());
875✔
2343
   j_jump(g, JIT_CC_T, cont);
875✔
2344

2345
   jit_handle_t handle = irgen_get_handle(g, n, 0);
875✔
2346

2347
   j_send(g, 0, old_state);
875✔
2348
   j_call(g, handle);
875✔
2349

2350
   jit_value_t new_state = j_recv(g, 0);
875✔
2351
   irgen_pcall_suspend(g, new_state, cont);
875✔
2352

2353
   irgen_bind_label(g, cont);
875✔
2354
}
875✔
2355

2356
static void irgen_op_wait(jit_irgen_t *g, mir_value_t n)
13,488✔
2357
{
2358
   if (mir_count_args(g->mu, n) > 1) {
13,488✔
2359
      jit_value_t after = irgen_get_arg(g, n, 1);
5,303✔
2360
      j_send(g, 0, after);
5,303✔
2361
      macro_exit(g, JIT_EXIT_SCHED_PROCESS);
5,303✔
2362
   }
2363

2364
   if (g->statereg.kind != JIT_VALUE_INVALID) {
13,488✔
2365
      mir_block_t target = mir_cast_block(mir_get_arg(g->mu, n, 0));
9,359✔
2366
      jit_value_t ptr = irgen_state_ptr(g);
9,359✔
2367
      j_store(g, JIT_SZ_32, jit_value_from_int64(target.id), ptr);
9,359✔
2368
   }
2369

2370
   if (mir_get_kind(g->mu) == MIR_UNIT_PROCEDURE)
13,488✔
2371
      j_send(g, 0, g->statereg);
265✔
2372
   else
2373
      j_send(g, 0, jit_value_from_int64(0));
13,223✔
2374

2375
   j_ret(g);
13,488✔
2376
}
13,488✔
2377

2378
static void irgen_op_protected_init(jit_irgen_t *g, mir_value_t n)
162✔
2379
{
2380
   jit_handle_t handle = irgen_get_handle(g, n, 0);
162✔
2381

2382
   irgen_send_args(g, n, 0);
162✔
2383
   j_call(g, handle);
162✔
2384

2385
   g->map[n.id] = j_recv(g, 0);
162✔
2386
}
162✔
2387

2388
static void irgen_op_reflect_value(jit_irgen_t *g, mir_value_t n)
45✔
2389
{
2390
   jit_value_t value = irgen_get_arg(g, n, 0);
45✔
2391
   jit_value_t context = irgen_get_arg(g, n, 1);
45✔
2392
   jit_value_t locus = irgen_get_arg(g, n, 2);
45✔
2393

2394
   j_send(g, 0, context);
45✔
2395
   j_send(g, 1, value);
45✔
2396
   j_send(g, 2, locus);
45✔
2397

2398
   if (mir_count_args(g->mu, n) > 3) {
45✔
2399
      mir_value_t bounds = mir_get_arg(g->mu, n, 3);
6✔
2400
      const int slots = irgen_slots_for_type(g, mir_get_type(g->mu, bounds));
6✔
2401
      if (slots > 1) {
6✔
2402
         jit_reg_t base = jit_value_as_reg(irgen_get_value(g, bounds));
6✔
2403
         for (int j = 0; j < slots; j++)
24✔
2404
            j_send(g, j + 3, jit_value_from_reg(base + j));
18✔
2405
      }
2406
      else
UNCOV
2407
         j_send(g, 3, irgen_get_value(g, bounds));
×
2408
   }
2409
   else
2410
      j_send(g, 3, value);
39✔
2411

2412
   macro_exit(g, JIT_EXIT_REFLECT_VALUE);
45✔
2413

2414
   g->map[n.id] = j_recv(g, 0);
45✔
2415
}
45✔
2416

2417
static void irgen_op_reflect_subtype(jit_irgen_t *g, mir_value_t n)
42✔
2418
{
2419
   jit_value_t context = irgen_get_arg(g, n, 0);
42✔
2420
   jit_value_t locus = irgen_get_arg(g, n, 1);
42✔
2421

2422
   j_send(g, 0, context);
42✔
2423
   j_send(g, 1, locus);
42✔
2424

2425
   if (mir_count_args(g->mu, n) > 2) {
42✔
2426
      mir_value_t bounds = mir_get_arg(g->mu, n, 2);
×
2427
      const int slots = irgen_slots_for_type(g, mir_get_type(g->mu, bounds));
×
2428
      if (slots > 1) {
×
2429
         jit_reg_t base = jit_value_as_reg(irgen_get_value(g, bounds));
×
2430
         for (int j = 0; j < slots; j++)
×
UNCOV
2431
            j_send(g, j + 2, jit_value_from_reg(base + j));
×
2432
      }
2433
      else
UNCOV
2434
         j_send(g, 2, irgen_get_value(g, bounds));
×
2435
   }
2436

2437
   macro_exit(g, JIT_EXIT_REFLECT_SUBTYPE);
42✔
2438

2439
   g->map[n.id] = j_recv(g, 0);
42✔
2440
}
42✔
2441

2442
static void irgen_op_process_init(jit_irgen_t *g, mir_value_t n)
112✔
2443
{
2444
   jit_handle_t handle = irgen_get_handle(g, n, 0);
112✔
2445
   jit_value_t locus = irgen_get_arg(g, n, 1);
112✔
2446

2447
   j_send(g, 0, jit_value_from_handle(handle));
112✔
2448
   j_send(g, 1, locus);
112✔
2449
   macro_exit(g, JIT_EXIT_PROCESS_INIT);
112✔
2450
}
112✔
2451

2452
static void irgen_op_index_check(jit_irgen_t *g, mir_value_t n)
11,085✔
2453
{
2454
   mir_value_t arg3 = mir_get_arg(g->mu, n, 3);
11,085✔
2455

2456
   jit_value_t value = irgen_get_arg(g, n, 0);
11,085✔
2457
   jit_value_t left  = irgen_get_arg(g, n, 1);
11,085✔
2458
   jit_value_t right = irgen_get_arg(g, n, 2);
11,085✔
2459
   jit_value_t dir   = irgen_get_value(g, arg3);
11,085✔
2460
   jit_value_t locus = irgen_get_arg(g, n, 4);
11,085✔
2461
   jit_value_t hint  = irgen_get_arg(g, n, 5);
11,085✔
2462

2463
   if (!mir_equals(arg3, g->flags))
11,085✔
2464
      j_cmp(g, JIT_CC_EQ, dir, jit_value_from_int64(RANGE_DOWNTO));
4,535✔
2465

2466
   jit_value_t low = j_csel(g, right, left);
11,085✔
2467
   jit_value_t high = j_csel(g, left, right);
11,085✔
2468

2469
   irgen_label_t *l_pass = irgen_alloc_label(g);
11,085✔
2470

2471
   j_cmp(g, JIT_CC_GE, value, low);
11,085✔
2472
   j_ccmp(g, JIT_CC_LE, value, high);
11,085✔
2473
   j_jump(g, JIT_CC_T, l_pass);
11,085✔
2474

2475
   j_send(g, 0, value);
11,085✔
2476
   j_send(g, 1, left);
11,085✔
2477
   j_send(g, 2, right);
11,085✔
2478
   j_send(g, 3, dir);
11,085✔
2479
   j_send(g, 4, locus);
11,085✔
2480
   j_send(g, 5, hint);
11,085✔
2481
   macro_exit(g, JIT_EXIT_INDEX_FAIL);
11,085✔
2482

2483
   irgen_bind_label(g, l_pass);
11,085✔
2484
}
11,085✔
2485

2486
static void irgen_op_range_check(jit_irgen_t *g, mir_value_t n)
3,019✔
2487
{
2488
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
3,019✔
2489
   mir_value_t arg3 = mir_get_arg(g->mu, n, 3);
3,019✔
2490

2491
   jit_value_t value = irgen_get_value(g, arg0);
3,019✔
2492
   jit_value_t left  = irgen_get_arg(g, n, 1);
3,019✔
2493
   jit_value_t right = irgen_get_arg(g, n, 2);
3,019✔
2494
   jit_value_t dir   = irgen_get_value(g, arg3);
3,019✔
2495
   jit_value_t locus = irgen_get_arg(g, n, 4);
3,019✔
2496
   jit_value_t hint  = irgen_get_arg(g, n, 5);
3,019✔
2497

2498
   if (!mir_equals(arg3, g->flags))
3,019✔
2499
      j_cmp(g, JIT_CC_EQ, dir, jit_value_from_int64(RANGE_DOWNTO));
2,880✔
2500

2501
   jit_value_t low = j_csel(g, right, left);
3,019✔
2502
   jit_value_t high = j_csel(g, left, right);
3,019✔
2503

2504
   irgen_label_t *l_fail = irgen_alloc_label(g);
3,019✔
2505
   irgen_label_t *l_pass = irgen_alloc_label(g);
3,019✔
2506

2507
   if (mir_is(g->mu, arg0, MIR_TYPE_REAL)) {
3,019✔
2508
      j_fcmp(g, JIT_CC_GE, value, low);
397✔
2509
      j_fccmp(g, JIT_CC_LE, value, high);
397✔
2510
      j_jump(g, JIT_CC_T, l_pass);
397✔
2511
   }
2512
   else {
2513
      j_cmp(g, JIT_CC_GE, value, low);
2,622✔
2514
      j_ccmp(g, JIT_CC_LE, value, high);
2,622✔
2515
      j_jump(g, JIT_CC_T, l_pass);
2,622✔
2516
   }
2517

2518
   irgen_bind_label(g, l_fail);
3,019✔
2519
   j_send(g, 0, value);
3,019✔
2520
   j_send(g, 1, left);
3,019✔
2521
   j_send(g, 2, right);
3,019✔
2522
   j_send(g, 3, dir);
3,019✔
2523
   j_send(g, 4, locus);
3,019✔
2524
   j_send(g, 5, hint);
3,019✔
2525
   macro_exit(g, JIT_EXIT_RANGE_FAIL);
3,019✔
2526

2527
   irgen_bind_label(g, l_pass);
3,019✔
2528
}
3,019✔
2529

2530
static void irgen_op_null_check(jit_irgen_t *g, mir_value_t n)
1,097✔
2531
{
2532
   jit_value_t ptr = irgen_get_arg(g, n, 0);
1,097✔
2533
   jit_value_t locus = irgen_get_arg(g, n, 1);
1,097✔
2534

2535
   irgen_label_t *l_pass = irgen_alloc_label(g);
1,097✔
2536

2537
   j_cmp(g, JIT_CC_NE, ptr, jit_value_from_int64(0));
1,097✔
2538
   j_jump(g, JIT_CC_T, l_pass);
1,097✔
2539

2540
   j_send(g, 0, locus);
1,097✔
2541
   macro_exit(g, JIT_EXIT_NULL_DEREF);
1,097✔
2542

2543
   irgen_bind_label(g, l_pass);
1,097✔
2544
}
1,097✔
2545

2546
static void irgen_op_zero_check(jit_irgen_t *g, mir_value_t n)
100✔
2547
{
2548
   jit_value_t value = irgen_get_arg(g, n, 0);
100✔
2549
   jit_value_t locus = irgen_get_arg(g, n, 1);
100✔
2550

2551
   irgen_label_t *l_pass = irgen_alloc_label(g);
100✔
2552

2553
   j_cmp(g, JIT_CC_NE, value, jit_value_from_int64(0));
100✔
2554
   j_jump(g, JIT_CC_T, l_pass);
100✔
2555

2556
   j_send(g, 0, locus);
100✔
2557
   macro_exit(g, JIT_EXIT_DIV_ZERO);
100✔
2558

2559
   irgen_bind_label(g, l_pass);
100✔
2560
}
100✔
2561

2562
static void irgen_op_exponent_check(jit_irgen_t *g, mir_value_t n)
513✔
2563
{
2564
   jit_value_t value = irgen_get_arg(g, n, 0);
513✔
2565
   jit_value_t locus = irgen_get_arg(g, n, 1);
513✔
2566

2567
   irgen_label_t *l_pass = irgen_alloc_label(g);
513✔
2568

2569
   j_cmp(g, JIT_CC_GE, value, jit_value_from_int64(0));
513✔
2570
   j_jump(g, JIT_CC_T, l_pass);
513✔
2571

2572
   j_send(g, 0, value);
513✔
2573
   j_send(g, 1, locus);
513✔
2574
   macro_exit(g, JIT_EXIT_EXPONENT_FAIL);
513✔
2575

2576
   irgen_bind_label(g, l_pass);
513✔
2577
}
513✔
2578

2579
static void irgen_op_length_check(jit_irgen_t *g, mir_value_t n)
6,744✔
2580
{
2581
   jit_value_t llen  = irgen_get_arg(g, n, 0);
6,744✔
2582
   jit_value_t rlen  = irgen_get_arg(g, n, 1);
6,744✔
2583
   jit_value_t locus = irgen_get_arg(g, n, 2);
6,744✔
2584

2585
   // TODO: why isn't this encoded with an enum?
2586
   jit_value_t dim;
6,744✔
2587
   if (mir_count_args(g->mu, n) > 3)
6,744✔
2588
      dim = irgen_get_arg(g, n, 3);
24✔
2589
   else
2590
      dim = jit_value_from_int64(0);
6,720✔
2591

2592
   irgen_label_t *l_pass = irgen_alloc_label(g);
6,744✔
2593

2594
   j_cmp(g, JIT_CC_EQ, llen, rlen);
6,744✔
2595
   j_jump(g, JIT_CC_T, l_pass);
6,744✔
2596

2597
   j_send(g, 0, llen);
6,744✔
2598
   j_send(g, 1, rlen);
6,744✔
2599
   j_send(g, 2, dim);
6,744✔
2600
   j_send(g, 3, locus);
6,744✔
2601
   macro_exit(g, JIT_EXIT_LENGTH_FAIL);
6,744✔
2602

2603
   irgen_bind_label(g, l_pass);
6,744✔
2604
}
6,744✔
2605

2606
static void irgen_op_package_init(jit_irgen_t *g, mir_value_t n)
17,595✔
2607
{
2608
   if (mir_count_args(g->mu, n) > 1)
17,595✔
2609
      j_send(g, 0, irgen_get_arg(g, n, 1));
182✔
2610
   else
2611
      j_send(g, 0, jit_value_from_int64(0));
17,413✔
2612

2613
   j_call(g, irgen_get_handle(g, n, 0));
17,595✔
2614

2615
   g->map[n.id] = j_recv(g, 0);
17,595✔
2616
}
17,595✔
2617

2618
static void irgen_op_link_package(jit_irgen_t *g, mir_value_t n)
11,397✔
2619
{
2620
   jit_handle_t handle = irgen_get_handle(g, n, 0);
11,397✔
2621

2622
   g->map[n.id] = macro_getpriv(g, handle);
11,397✔
2623
}
11,397✔
2624

2625
static void irgen_op_link_var(jit_irgen_t *g, mir_value_t n)
2,522✔
2626
{
2627
   jit_handle_t handle = irgen_get_handle(g, n, 0);
2,522✔
2628
   jit_value_t context = irgen_get_arg(g, n, 1);
2,522✔
2629
   ident_t var_name = mir_get_name(g->mu, mir_get_arg(g->mu, n, 2));
2,522✔
2630

2631
   jit_func_t *f = jit_get_func(g->func->jit, handle);
2,522✔
2632
   jit_fill_irbuf(f);
2,522✔
2633

2634
   link_tab_t *tab = f->linktab;
2,522✔
2635
   for (; tab < f->linktab + f->nvars; tab++) {
33,768✔
2636
      if (tab->name == var_name)
33,768✔
2637
         break;
2638
   }
2639

2640
   if (tab == f->linktab + f->nvars)
2,522✔
2641
      fatal_trace("variable %s not found in unit %s", istr(var_name),
2642
                  istr(f->name));
2643

2644
   g->map[n.id] = jit_addr_from_value(context, tab->offset);
2,522✔
2645
}
2,522✔
2646

2647
static void irgen_op_new(jit_irgen_t *g, mir_value_t n)
410✔
2648
{
2649
   mir_type_t elem = mir_get_elem(g->mu, mir_get_type(g->mu, n));
410✔
2650

2651
   int headersz = 0;
410✔
2652
   if (mir_get_class(g->mu, elem) == MIR_TYPE_UARRAY) {
410✔
2653
      headersz = irgen_size_bytes(g, elem);
230✔
2654
      elem = mir_get_elem(g->mu, elem);
230✔
2655
   }
2656

2657
   jit_value_t bytes = jit_value_from_int64(irgen_size_bytes(g, elem));
410✔
2658

2659
   irgen_emit_debuginfo(g, n);   // For out-of-memory stack traces
410✔
2660

2661
   if (mir_count_args(g->mu, n) > 0)
410✔
2662
      bytes = j_mul(g, bytes, irgen_get_arg(g, n, 0));
323✔
2663

2664
   if (headersz > 0)
410✔
2665
      bytes = j_add(g, bytes, jit_value_from_int64(headersz));
230✔
2666

2667
   jit_value_t mem = macro_galloc(g, bytes);
410✔
2668
   g->map[n.id] = mem;
410✔
2669

2670
   if (headersz > 0) {
410✔
2671
      // Initialise the header to point at the body
2672
      jit_value_t ptr = jit_addr_from_value(mem, 0);
230✔
2673
      jit_value_t body = j_add(g, mem, jit_value_from_int64(headersz));
230✔
2674
      j_store(g, JIT_SZ_PTR, body, ptr);
230✔
2675
   }
2676
}
410✔
2677

2678
static void irgen_op_alloc(jit_irgen_t *g, mir_value_t n)
7,239✔
2679
{
2680
   mir_type_t type = mir_get_pointer(g->mu, mir_get_type(g->mu, n));
7,239✔
2681

2682
   const int bytes = irgen_size_bytes(g, type);
7,239✔
2683

2684
   jit_value_t count = irgen_get_arg(g, n, 0);
7,239✔
2685
   jit_value_t total = j_mul(g, count, jit_value_from_int64(bytes));
7,239✔
2686

2687
   g->map[n.id] = macro_lalloc(g, total);
7,239✔
2688
   g->used_tlab = true;
7,239✔
2689
}
7,239✔
2690

2691
static void irgen_op_all(jit_irgen_t *g, mir_value_t n)
1,507✔
2692
{
2693
   jit_value_t arg = irgen_get_arg(g, n, 0);
1,507✔
2694
   g->map[n.id] = jit_addr_from_value(arg, 0);
1,507✔
2695
}
1,507✔
2696

2697
static void irgen_op_closure(jit_irgen_t *g, mir_value_t n)
1,355✔
2698
{
2699
   jit_handle_t handle = irgen_get_handle(g, n, 0);
1,355✔
2700

2701
   jit_reg_t base = irgen_alloc_reg(g);
1,355✔
2702
   j_mov(g, base, jit_value_from_handle(handle));
1,355✔
2703

2704
   jit_reg_t context = irgen_alloc_reg(g);
1,355✔
2705
   j_mov(g, context, irgen_get_arg(g, n, 1));
1,355✔
2706

2707
   g->map[n.id] = jit_value_from_reg(base);
1,355✔
2708
}
1,355✔
2709

2710
static void irgen_op_resolution_wrapper(jit_irgen_t *g, mir_value_t n)
983✔
2711
{
2712
   jit_value_t closure = irgen_get_arg(g, n, 0);
983✔
2713

2714
   jit_reg_t base = irgen_alloc_reg(g);
983✔
2715
   j_mov(g, base, closure);
983✔
2716

2717
   jit_reg_t context = irgen_alloc_reg(g);
983✔
2718
   j_mov(g, context, jit_value_from_reg(jit_value_as_reg(closure) + 1));
983✔
2719

2720
   jit_reg_t ileft = irgen_alloc_reg(g);
983✔
2721
   j_mov(g, ileft, irgen_get_arg(g, n, 1));
983✔
2722

2723
   jit_reg_t nlits = irgen_alloc_reg(g);
983✔
2724
   j_mov(g, nlits, irgen_get_arg(g, n, 2));
983✔
2725

2726
   mir_type_t type = mir_get_base(g->mu, mir_get_type(g->mu, n));
983✔
2727

2728
   uint32_t flagbits = 0;
983✔
2729
   if (mir_get_class(g->mu, type) == MIR_TYPE_POINTER)
983✔
2730
      flagbits |= R_COMPOSITE;
27✔
2731

2732
   jit_reg_t flags = irgen_alloc_reg(g);
983✔
2733
   j_mov(g, flags, jit_value_from_int64(flagbits));
983✔
2734

2735
   g->map[n.id] = jit_value_from_reg(base);
983✔
2736
}
983✔
2737

2738
static void irgen_op_init_signal(jit_irgen_t *g, mir_value_t n)
16,184✔
2739
{
2740
   jit_value_t count = irgen_get_arg(g, n, 0);
16,184✔
2741
   jit_value_t size  = irgen_get_arg(g, n, 1);
16,184✔
2742
   jit_value_t value = irgen_get_arg(g, n, 2);
16,184✔
2743
   jit_value_t flags = irgen_get_arg(g, n, 3);
16,184✔
2744
   jit_value_t locus = irgen_get_arg(g, n, 4);
16,184✔
2745

2746
   jit_value_t offset;
16,184✔
2747
   if (mir_count_args(g->mu, n) > 5)
16,184✔
2748
      offset = irgen_get_arg(g, n, 5);
5,605✔
2749
   else
2750
      offset = jit_value_from_int64(0);
10,579✔
2751

2752
   jit_value_t scalar = irgen_is_scalar(g, n, 2);
16,184✔
2753

2754
   j_send(g, 0, count);
16,184✔
2755
   j_send(g, 1, size);
16,184✔
2756
   j_send(g, 2, value);
16,184✔
2757
   j_send(g, 3, flags);
16,184✔
2758
   j_send(g, 4, locus);
16,184✔
2759
   j_send(g, 5, offset);
16,184✔
2760
   j_send(g, 6, scalar);
16,184✔
2761

2762
   macro_exit(g, JIT_EXIT_INIT_SIGNAL);
16,184✔
2763

2764
   g->map[n.id] = j_recv(g, 0);
16,184✔
2765

2766
   // Offset into signal must be next sequential register
2767
   jit_reg_t next = irgen_alloc_reg(g);
16,184✔
2768
   j_mov(g, next, jit_value_from_int64(0));
16,184✔
2769
}
16,184✔
2770

2771
static void irgen_op_implicit_signal(jit_irgen_t *g, mir_value_t n)
75✔
2772
{
2773
   jit_value_t count   = irgen_get_arg(g, n, 0);
75✔
2774
   jit_value_t size    = irgen_get_arg(g, n, 1);
75✔
2775
   jit_value_t locus   = irgen_get_arg(g, n, 2);
75✔
2776
   jit_value_t kind    = irgen_get_arg(g, n, 3);
75✔
2777
   jit_value_t closure = irgen_get_arg(g, n, 4);
75✔
2778
   jit_value_t context = jit_value_from_reg(jit_value_as_reg(closure) + 1);
75✔
2779
   jit_value_t delay   = irgen_get_arg(g, n, 5);
75✔
2780

2781
   j_send(g, 0, count);
75✔
2782
   j_send(g, 1, size);
75✔
2783
   j_send(g, 2, locus);
75✔
2784
   j_send(g, 3, kind);
75✔
2785
   j_send(g, 4, closure);
75✔
2786
   j_send(g, 5, context);
75✔
2787
   j_send(g, 6, delay);
75✔
2788

2789
   macro_exit(g, JIT_EXIT_IMPLICIT_SIGNAL);
75✔
2790

2791
   g->map[n.id] = j_recv(g, 0);
75✔
2792

2793
   // Offset into signal must be next sequential register
2794
   jit_reg_t next = irgen_alloc_reg(g);
75✔
2795
   j_mov(g, next, jit_value_from_int64(0));
75✔
2796
}
75✔
2797

2798
static void irgen_op_alias_signal(jit_irgen_t *g, mir_value_t n)
4,232✔
2799
{
2800
   jit_value_t shared = irgen_get_arg(g, n, 0);
4,232✔
2801
   jit_value_t locus  = irgen_get_arg(g, n, 1);
4,232✔
2802

2803
   j_send(g, 0, shared);
4,232✔
2804
   j_send(g, 1, locus);
4,232✔
2805

2806
   macro_exit(g, JIT_EXIT_ALIAS_SIGNAL);
4,232✔
2807
}
4,232✔
2808

2809
static void irgen_op_map_signal(jit_irgen_t *g, mir_value_t n)
5,322✔
2810
{
2811
   jit_value_t src_ss  = irgen_get_arg(g, n, 0);
5,322✔
2812
   jit_value_t src_off = jit_value_from_reg(jit_value_as_reg(src_ss) + 1);
5,322✔
2813
   jit_value_t dst_ss  = irgen_get_arg(g, n, 1);
5,322✔
2814
   jit_value_t dst_off = jit_value_from_reg(jit_value_as_reg(dst_ss) + 1);
5,322✔
2815
   jit_value_t count   = irgen_get_arg(g, n, 2);
5,322✔
2816

2817
   j_send(g, 0, src_ss);
5,322✔
2818
   j_send(g, 1, src_off);
5,322✔
2819
   j_send(g, 2, dst_ss);
5,322✔
2820
   j_send(g, 3, dst_off);
5,322✔
2821
   j_send(g, 4, count);
5,322✔
2822

2823
   macro_exit(g, JIT_EXIT_MAP_SIGNAL);
5,322✔
2824
}
5,322✔
2825

2826
static void irgen_op_map_const(jit_irgen_t *g, mir_value_t n)
219✔
2827
{
2828
   jit_value_t initval   = irgen_get_arg(g, n, 0);
219✔
2829
   jit_value_t dst_ss    = irgen_get_arg(g, n, 1);
219✔
2830
   jit_value_t dst_off   = jit_value_from_reg(jit_value_as_reg(dst_ss) + 1);
219✔
2831
   jit_value_t dst_count = irgen_get_arg(g, n, 2);
219✔
2832

2833
   jit_value_t scalar = irgen_is_scalar(g, n, 0);
219✔
2834

2835
   j_send(g, 0, dst_ss);
219✔
2836
   j_send(g, 1, dst_off);
219✔
2837
   j_send(g, 2, initval);
219✔
2838
   j_send(g, 3, dst_count);
219✔
2839
   j_send(g, 4, scalar);
219✔
2840

2841
   macro_exit(g, JIT_EXIT_MAP_CONST);
219✔
2842
}
219✔
2843

2844
static void irgen_op_map_implicit(jit_irgen_t *g, mir_value_t n)
57✔
2845
{
2846
   jit_value_t src_ss  = irgen_get_arg(g, n, 0);
57✔
2847
   jit_value_t src_off = jit_value_from_reg(jit_value_as_reg(src_ss) + 1);
57✔
2848
   jit_value_t dst_ss  = irgen_get_arg(g, n, 1);
57✔
2849
   jit_value_t dst_off = jit_value_from_reg(jit_value_as_reg(dst_ss) + 1);
57✔
2850
   jit_value_t count   = irgen_get_arg(g, n, 2);
57✔
2851

2852
   j_send(g, 0, src_ss);
57✔
2853
   j_send(g, 1, src_off);
57✔
2854
   j_send(g, 2, dst_ss);
57✔
2855
   j_send(g, 3, dst_off);
57✔
2856
   j_send(g, 4, count);
57✔
2857

2858
   macro_exit(g, JIT_EXIT_MAP_IMPLICIT);
57✔
2859
}
57✔
2860

2861
static void irgen_op_resolve_signal(jit_irgen_t *g, mir_value_t n)
3,451✔
2862
{
2863
   jit_value_t shared  = irgen_get_arg(g, n, 0);
3,451✔
2864
   jit_value_t resfn   = irgen_get_arg(g, n, 1);
3,451✔
2865
   jit_reg_t   base    = jit_value_as_reg(resfn);
3,451✔
2866
   jit_value_t context = jit_value_from_reg(base + 1);
3,451✔
2867
   jit_value_t ileft   = jit_value_from_reg(base + 2);
3,451✔
2868
   jit_value_t nlits   = jit_value_from_reg(base + 3);
3,451✔
2869
   jit_value_t flags   = jit_value_from_reg(base + 4);
3,451✔
2870

2871
   j_send(g, 0, shared);
3,451✔
2872
   j_send(g, 1, resfn);
3,451✔
2873
   j_send(g, 2, context);
3,451✔
2874
   j_send(g, 3, ileft);
3,451✔
2875
   j_send(g, 4, nlits);
3,451✔
2876
   j_send(g, 5, flags);
3,451✔
2877

2878
   macro_exit(g, JIT_EXIT_RESOLVE_SIGNAL);
3,451✔
2879
}
3,451✔
2880

2881
static void irgen_op_unreachable(jit_irgen_t *g, mir_value_t n)
595✔
2882
{
2883
   jit_value_t locus;
595✔
2884
   if (mir_count_args(g->mu, n) > 0)
595✔
2885
      locus = irgen_get_arg(g, n, 0);
132✔
2886
   else
2887
      locus = jit_value_from_int64(0);
463✔
2888

2889
   j_send(g, 0, locus);
595✔
2890
   macro_exit(g, JIT_EXIT_UNREACHABLE);
595✔
2891
}
595✔
2892

2893
static void irgen_op_report(jit_irgen_t *g, mir_value_t n)
2,244✔
2894
{
2895
   jit_value_t severity = irgen_get_arg(g, n, 0);
2,244✔
2896
   jit_value_t msg      = irgen_get_arg(g, n, 1);
2,244✔
2897
   jit_value_t length   = irgen_get_arg(g, n, 2);
2,244✔
2898
   jit_value_t locus    = irgen_get_arg(g, n, 3);
2,244✔
2899

2900
   j_send(g, 0, msg);
2,244✔
2901
   j_send(g, 1, length);
2,244✔
2902
   j_send(g, 2, severity);
2,244✔
2903
   j_send(g, 3, locus);
2,244✔
2904
   macro_exit(g, JIT_EXIT_REPORT);
2,244✔
2905
}
2,244✔
2906

2907
static void irgen_op_assert(jit_irgen_t *g, mir_value_t n)
14,001✔
2908
{
2909
   jit_value_t severity = irgen_get_arg(g, n, 1);
14,001✔
2910
   jit_value_t locus    = irgen_get_arg(g, n, 4);
14,001✔
2911

2912
   // TODO: having null arguments sucks - why not have optional args?
2913
   jit_value_t msg    = jit_value_from_int64(0);
14,001✔
2914
   jit_value_t length = jit_value_from_int64(0);
14,001✔
2915
   if (!mir_is_null(mir_get_arg(g->mu, n, 2))) {
14,001✔
2916
      msg    = irgen_get_arg(g, n, 2);
3,647✔
2917
      length = irgen_get_arg(g, n, 3);
3,647✔
2918
   }
2919

2920
   jit_value_t hint_left, hint_right, hint_valid;
14,001✔
2921
   if (mir_count_args(g->mu, n) > 5) {
14,001✔
2922
      hint_left  = irgen_get_arg(g, n, 5);
5,753✔
2923
      hint_right = irgen_get_arg(g, n, 6);
5,753✔
2924
      hint_valid = jit_value_from_int64(true);
5,753✔
2925
   }
2926
   else {
2927
      hint_left = hint_right = jit_value_from_int64(0);
8,248✔
2928
      hint_valid = jit_value_from_int64(false);
8,248✔
2929
   }
2930

2931
   irgen_label_t *l_pass = irgen_alloc_label(g);
14,001✔
2932

2933
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
14,001✔
2934
   if (!mir_equals(arg0, g->flags)) {
14,001✔
2935
      jit_value_t test = irgen_get_value(g, arg0);
7,426✔
2936
      j_cmp(g, JIT_CC_NE, test, jit_value_from_int64(0));
7,426✔
2937
   }
2938

2939
   j_jump(g, JIT_CC_T, l_pass);
14,001✔
2940

2941
   j_send(g, 0, msg);
14,001✔
2942
   j_send(g, 1, length);
14,001✔
2943
   j_send(g, 2, severity);
14,001✔
2944
   j_send(g, 3, hint_left);
14,001✔
2945
   j_send(g, 4, hint_right);
14,001✔
2946
   j_send(g, 5, hint_valid);
14,001✔
2947
   j_send(g, 6, locus);
14,001✔
2948
   macro_exit(g, JIT_EXIT_ASSERT_FAIL);
14,001✔
2949

2950
   irgen_bind_label(g, l_pass);
14,001✔
2951
}
14,001✔
2952

2953
static void irgen_op_file_open(jit_irgen_t *g, mir_value_t n)
261✔
2954
{
2955
   jit_value_t file   = irgen_get_arg(g, n, 0);
261✔
2956
   jit_value_t name   = irgen_get_arg(g, n, 1);
261✔
2957
   jit_value_t length = irgen_get_arg(g, n, 2);
261✔
2958
   jit_value_t kind   = irgen_get_arg(g, n, 3);
261✔
2959

2960
   irgen_emit_debuginfo(g, n);   // For stack traces
261✔
2961

2962
   jit_value_t status = jit_null_ptr();
261✔
2963
   if (mir_count_args(g->mu, n) == 5)
261✔
2964
      status = irgen_get_arg(g, n, 4);
26✔
2965

2966
   j_send(g, 0, status);
261✔
2967
   j_send(g, 1, file);
261✔
2968
   j_send(g, 2, name);
261✔
2969
   j_send(g, 3, length);
261✔
2970
   j_send(g, 4, kind);
261✔
2971

2972
   macro_exit(g, JIT_EXIT_FILE_OPEN);
261✔
2973
}
261✔
2974

2975
static void irgen_op_file_read(jit_irgen_t *g, mir_value_t n)
75✔
2976
{
2977
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
75✔
2978
   mir_value_t arg1 = mir_get_arg(g->mu, n, 1);
75✔
2979

2980
   jit_value_t file = irgen_get_value(g, arg0);
75✔
2981
   jit_value_t ptr  = irgen_get_value(g, arg1);
75✔
2982

2983
   jit_value_t count = jit_value_from_int64(1);
75✔
2984
   if (mir_count_args(g->mu, n) >= 3)
75✔
2985
      count = irgen_get_arg(g, n, 2);
27✔
2986

2987
   mir_type_t file_type = mir_get_elem(g->mu, mir_get_type(g->mu, arg0));
75✔
2988
   assert(mir_get_class(g->mu, file_type) == MIR_TYPE_FILE);
75✔
2989

2990
   mir_type_t elem_type = mir_get_base(g->mu, file_type);
75✔
2991
   switch (mir_get_class(g->mu, elem_type)) {
75✔
2992
   case MIR_TYPE_UARRAY:
27✔
2993
   case MIR_TYPE_CARRAY:
2994
      elem_type = mir_get_elem(g->mu, elem_type);
27✔
2995
      break;
27✔
2996
   default:
2997
      break;
2998
   }
2999

3000
   jit_value_t size = jit_value_from_int64(irgen_size_bytes(g, elem_type));
75✔
3001

3002
   j_send(g, 0, file);
75✔
3003
   j_send(g, 1, ptr);
75✔
3004
   j_send(g, 2, size);
75✔
3005
   j_send(g, 3, count);
75✔
3006

3007
   macro_exit(g, JIT_EXIT_FILE_READ);
75✔
3008

3009
   if (mir_count_args(g->mu, n) >= 4) {
75✔
3010
      mir_value_t arg3 = mir_get_arg(g->mu, n, 3);
18✔
3011
      mir_type_t out_type = mir_get_elem(g->mu, mir_get_type(g->mu, arg3));
18✔
3012
      jit_size_t out_size = irgen_jit_size(g, out_type);
18✔
3013

3014
      jit_value_t outarg = irgen_get_value(g, arg3);
18✔
3015
      jit_value_t outptr = jit_addr_from_value(outarg, 0);
18✔
3016
      jit_value_t len = j_recv(g, 0);
18✔
3017
      j_store(g, out_size, len, outptr);
18✔
3018
   }
3019
}
75✔
3020

3021
static void irgen_op_file_write(jit_irgen_t *g, mir_value_t n)
122✔
3022
{
3023
   mir_value_t arg0 = mir_get_arg(g->mu, n, 0);
122✔
3024
   mir_value_t arg1 = mir_get_arg(g->mu, n, 1);
122✔
3025

3026
   jit_value_t file = irgen_get_value(g, arg0);
122✔
3027
   jit_value_t data = irgen_get_value(g, arg1);
122✔
3028

3029
   jit_value_t count;
122✔
3030
   if (mir_count_args(g->mu, n) > 2)
122✔
3031
      count = irgen_get_arg(g, n, 2);
65✔
3032
   else
3033
      count = jit_value_from_int64(1);
57✔
3034

3035
   mir_type_t file_type = mir_get_elem(g->mu, mir_get_type(g->mu, arg0));
122✔
3036
   assert(mir_get_class(g->mu, file_type) == MIR_TYPE_FILE);
122✔
3037

3038
   mir_type_t elem_type = mir_get_base(g->mu, file_type);
122✔
3039
   switch (mir_get_class(g->mu, elem_type)) {
122✔
3040
   case MIR_TYPE_UARRAY:
65✔
3041
   case MIR_TYPE_CARRAY:
3042
      elem_type = mir_get_elem(g->mu, elem_type);
65✔
3043
      break;
65✔
3044
   default:
3045
      break;
3046
   }
3047

3048
   jit_value_t bytes = jit_value_from_int64(irgen_size_bytes(g, elem_type));
122✔
3049
   jit_value_t scalar = jit_value_from_int64(mir_is_scalar(g->mu, arg1));
122✔
3050

3051
   j_send(g, 0, file);
122✔
3052
   j_send(g, 1, data);
122✔
3053
   j_send(g, 2, bytes);
122✔
3054
   j_send(g, 3, count);
122✔
3055
   j_send(g, 4, scalar);
122✔
3056

3057
   macro_exit(g, JIT_EXIT_FILE_WRITE);
122✔
3058
}
122✔
3059

3060
static void irgen_op_package_scope(jit_irgen_t *g, mir_value_t n)
45✔
3061
{
3062
   jit_value_t locus = irgen_get_arg(g, n, 0);
45✔
3063
   j_send(g, 0, locus);
45✔
3064
   j_send(g, 2, jit_value_from_int64(0));
45✔
3065
   j_send(g, 2, jit_value_from_int64(SCOPE_PACKAGE));
45✔
3066

3067
   macro_exit(g, JIT_EXIT_PUSH_SCOPE);
45✔
3068
}
45✔
3069

3070
static void irgen_op_array_scope(jit_irgen_t *g, mir_value_t n)
632✔
3071
{
3072
   jit_value_t locus = irgen_get_arg(g, n, 0);
632✔
3073
   j_send(g, 0, locus);
632✔
3074

3075
   const int size = irgen_size_bytes(g, mir_get_type(g->mu, n));
632✔
3076
   j_send(g, 1, jit_value_from_int64(size));
632✔
3077
   j_send(g, 2, jit_value_from_int64(SCOPE_ARRAY));
632✔
3078

3079
   macro_exit(g, JIT_EXIT_PUSH_SCOPE);
632✔
3080
}
632✔
3081

3082
static void irgen_op_record_scope(jit_irgen_t *g, mir_value_t n)
1,606✔
3083
{
3084
   jit_value_t locus = irgen_get_arg(g, n, 0);
1,606✔
3085
   j_send(g, 0, locus);
1,606✔
3086

3087
   const int size = irgen_size_bytes(g, mir_get_type(g->mu, n));
1,606✔
3088
   j_send(g, 1, jit_value_from_int64(size));
1,606✔
3089
   j_send(g, 2, jit_value_from_int64(SCOPE_RECORD));
1,606✔
3090

3091
   macro_exit(g, JIT_EXIT_PUSH_SCOPE);
1,606✔
3092
}
1,606✔
3093

3094
static void irgen_op_pop_scope(jit_irgen_t *g, mir_value_t n)
2,283✔
3095
{
3096
   macro_exit(g, JIT_EXIT_POP_SCOPE);
2,283✔
3097
}
2,283✔
3098

3099
static void irgen_op_drive_signal(jit_irgen_t *g, mir_value_t n)
9,197✔
3100
{
3101
   jit_value_t shared = irgen_get_arg(g, n, 0);
9,197✔
3102
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
9,197✔
3103
   jit_value_t count  = irgen_get_arg(g, n, 1);
9,197✔
3104

3105
   j_send(g, 0, shared);
9,197✔
3106
   j_send(g, 1, offset);
9,197✔
3107
   j_send(g, 2, count);
9,197✔
3108
   macro_exit(g, JIT_EXIT_DRIVE_SIGNAL);
9,197✔
3109
}
9,197✔
3110

3111
static void irgen_op_transfer_signal(jit_irgen_t *g, mir_value_t n)
1,160✔
3112
{
3113
   jit_value_t target  = irgen_get_arg(g, n, 0);
1,160✔
3114
   jit_value_t toffset = jit_value_from_reg(jit_value_as_reg(target) + 1);
1,160✔
3115
   jit_value_t source  = irgen_get_arg(g, n, 1);
1,160✔
3116
   jit_value_t soffset = jit_value_from_reg(jit_value_as_reg(source) + 1);
1,160✔
3117
   jit_value_t count   = irgen_get_arg(g, n, 2);
1,160✔
3118
   jit_value_t reject  = irgen_get_arg(g, n, 3);
1,160✔
3119
   jit_value_t after   = irgen_get_arg(g, n, 4);
1,160✔
3120

3121
   j_send(g, 0, target);
1,160✔
3122
   j_send(g, 1, toffset);
1,160✔
3123
   j_send(g, 2, source);
1,160✔
3124
   j_send(g, 3, soffset);
1,160✔
3125
   j_send(g, 4, count);
1,160✔
3126
   j_send(g, 5, after);
1,160✔
3127
   j_send(g, 6, reject);
1,160✔
3128

3129
   macro_exit(g, JIT_EXIT_TRANSFER_SIGNAL);
1,160✔
3130
}
1,160✔
3131

3132
static void irgen_op_resolved(jit_irgen_t *g, mir_value_t n)
14,108✔
3133
{
3134
   jit_value_t shared = irgen_get_arg(g, n, 0);
14,108✔
3135
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
14,108✔
3136

3137
   jit_value_t data_ptr = irgen_lea(g, jit_addr_from_value(shared, 8));
14,108✔
3138

3139
   mir_type_t type = mir_get_pointer(g->mu, mir_get_type(g->mu, n));
14,108✔
3140

3141
   const int scale = irgen_size_bytes(g, type);
14,108✔
3142
   jit_value_t scaled = j_mul(g, offset, jit_value_from_int64(scale));
14,108✔
3143

3144
   g->map[n.id] = j_add(g, data_ptr, scaled);
14,108✔
3145
}
14,108✔
3146

3147
static void irgen_op_last_value(jit_irgen_t *g, mir_value_t n)
90✔
3148
{
3149
   jit_value_t shared = irgen_get_arg(g, n, 0);
90✔
3150
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
90✔
3151

3152
   jit_value_t data_ptr = irgen_lea(g, jit_addr_from_value(shared, 8));
90✔
3153
   jit_value_t size = j_load(g, JIT_SZ_32, jit_addr_from_value(shared, 0));
90✔
3154

3155
   jit_value_t last_value = j_add(g, data_ptr, size);
90✔
3156

3157
   mir_type_t type = mir_get_elem(g->mu, mir_get_type(g->mu, n));
90✔
3158

3159
   const int scale = irgen_size_bytes(g, type);
90✔
3160
   jit_value_t scaled = j_mul(g, offset, jit_value_from_int64(scale));
90✔
3161

3162
   g->map[n.id] = j_add(g, last_value, scaled);
90✔
3163
}
90✔
3164

3165
static void irgen_op_sched_waveform(jit_irgen_t *g, mir_value_t n)
10,611✔
3166
{
3167
   jit_value_t shared = irgen_get_arg(g, n, 0);
10,611✔
3168
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
10,611✔
3169
   jit_value_t count  = irgen_get_arg(g, n, 1);
10,611✔
3170
   jit_value_t value  = irgen_get_arg(g, n, 2);
10,611✔
3171
   jit_value_t reject = irgen_get_arg(g, n, 3);
10,611✔
3172
   jit_value_t after  = irgen_get_arg(g, n, 4);
10,611✔
3173

3174
   jit_value_t scalar = irgen_is_scalar(g, n, 2);
10,611✔
3175

3176
   j_send(g, 0, shared);
10,611✔
3177
   j_send(g, 1, offset);
10,611✔
3178
   j_send(g, 2, count);
10,611✔
3179
   j_send(g, 3, value);
10,611✔
3180
   j_send(g, 4, after);
10,611✔
3181
   j_send(g, 5, reject);
10,611✔
3182
   j_send(g, 6, scalar);
10,611✔
3183

3184
   macro_exit(g, JIT_EXIT_SCHED_WAVEFORM);
10,611✔
3185
}
10,611✔
3186

3187
static void irgen_op_disconnect(jit_irgen_t *g, mir_value_t n)
24✔
3188
{
3189
   jit_value_t shared = irgen_get_arg(g, n, 0);
24✔
3190
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
24✔
3191
   jit_value_t count  = irgen_get_arg(g, n, 1);
24✔
3192
   jit_value_t reject = irgen_get_arg(g, n, 2);
24✔
3193
   jit_value_t after  = irgen_get_arg(g, n, 3);
24✔
3194

3195
   j_send(g, 0, shared);
24✔
3196
   j_send(g, 1, offset);
24✔
3197
   j_send(g, 2, count);
24✔
3198
   j_send(g, 3, reject);
24✔
3199
   j_send(g, 4, after);
24✔
3200

3201
   macro_exit(g, JIT_EXIT_DISCONNECT);
24✔
3202
}
24✔
3203

3204
static void irgen_op_force(jit_irgen_t *g, mir_value_t n)
60✔
3205
{
3206
   jit_value_t shared = irgen_get_arg(g, n, 0);
60✔
3207
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
60✔
3208
   jit_value_t count  = irgen_get_arg(g, n, 1);
60✔
3209
   jit_value_t value  = irgen_get_arg(g, n, 2);
60✔
3210

3211
   jit_value_t scalar = irgen_is_scalar(g, n, 2);
60✔
3212

3213
   j_send(g, 0, shared);
60✔
3214
   j_send(g, 1, offset);
60✔
3215
   j_send(g, 2, count);
60✔
3216
   j_send(g, 3, value);
60✔
3217
   j_send(g, 4, scalar);
60✔
3218

3219
   macro_exit(g, JIT_EXIT_FORCE);
60✔
3220
}
60✔
3221

3222
static void irgen_op_release(jit_irgen_t *g, mir_value_t n)
30✔
3223
{
3224
   jit_value_t shared = irgen_get_arg(g, n, 0);
30✔
3225
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
30✔
3226
   jit_value_t count  = irgen_get_arg(g, n, 1);
30✔
3227

3228
   j_send(g, 0, shared);
30✔
3229
   j_send(g, 1, offset);
30✔
3230
   j_send(g, 2, count);
30✔
3231

3232
   macro_exit(g, JIT_EXIT_RELEASE);
30✔
3233
}
30✔
3234

3235
static void irgen_op_deposit_signal(jit_irgen_t *g, mir_value_t n)
177✔
3236
{
3237
   jit_value_t shared = irgen_get_arg(g, n, 0);
177✔
3238
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
177✔
3239
   jit_value_t count  = irgen_get_arg(g, n, 1);
177✔
3240
   jit_value_t value  = irgen_get_arg(g, n, 2);
177✔
3241

3242
   jit_value_t scalar = irgen_is_scalar(g, n, 2);
177✔
3243

3244
   j_send(g, 0, shared);
177✔
3245
   j_send(g, 1, offset);
177✔
3246
   j_send(g, 2, count);
177✔
3247
   j_send(g, 3, value);
177✔
3248
   j_send(g, 4, scalar);
177✔
3249

3250
   macro_exit(g, JIT_EXIT_DEPOSIT_SIGNAL);
177✔
3251
}
177✔
3252

3253
static void irgen_op_put_conversion(jit_irgen_t *g, mir_value_t n)
402✔
3254
{
3255
   jit_value_t cf     = irgen_get_arg(g, n, 0);
402✔
3256
   jit_value_t shared = irgen_get_arg(g, n, 1);
402✔
3257
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
402✔
3258
   jit_value_t count  = irgen_get_arg(g, n, 2);
402✔
3259
   jit_value_t value  = irgen_get_arg(g, n, 3);
402✔
3260

3261
   jit_value_t scalar = irgen_is_scalar(g, n, 3);
402✔
3262

3263
   j_send(g, 0, cf);
402✔
3264
   j_send(g, 1, shared);
402✔
3265
   j_send(g, 2, offset);
402✔
3266
   j_send(g, 3, count);
402✔
3267
   j_send(g, 4, value);
402✔
3268
   j_send(g, 5, scalar);
402✔
3269

3270
   macro_exit(g, JIT_EXIT_PUT_CONVERSION);
402✔
3271
}
402✔
3272

3273
static void irgen_op_sched_event(jit_irgen_t *g, mir_value_t n)
5,813✔
3274
{
3275
   jit_value_t shared = irgen_get_arg(g, n, 0);
5,813✔
3276
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
5,813✔
3277
   jit_value_t count  = irgen_get_arg(g, n, 1);
5,813✔
3278

3279
   j_send(g, 0, shared);
5,813✔
3280
   j_send(g, 1, offset);
5,813✔
3281
   j_send(g, 2, count);
5,813✔
3282
   macro_exit(g, JIT_EXIT_SCHED_EVENT);
5,813✔
3283
}
5,813✔
3284

3285
static void irgen_op_clear_event(jit_irgen_t *g, mir_value_t n)
499✔
3286
{
3287
   jit_value_t shared = irgen_get_arg(g, n, 0);
499✔
3288
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
499✔
3289
   jit_value_t count  = irgen_get_arg(g, n, 1);
499✔
3290

3291
   j_send(g, 0, shared);
499✔
3292
   j_send(g, 1, offset);
499✔
3293
   j_send(g, 2, count);
499✔
3294
   macro_exit(g, JIT_EXIT_CLEAR_EVENT);
499✔
3295
}
499✔
3296

3297
static void irgen_op_event(jit_irgen_t *g, mir_value_t n)
411✔
3298
{
3299
   jit_value_t shared = irgen_get_arg(g, n, 0);
411✔
3300
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
411✔
3301
   jit_value_t count  = irgen_get_arg(g, n, 1);
411✔
3302

3303
   jit_value_t flags = j_load(g, JIT_SZ_32, jit_addr_from_value(shared, 4));
411✔
3304

3305
   jit_value_t cachebit = jit_value_from_int64(SIG_F_CACHE_EVENT);
411✔
3306
   jit_value_t cacheflag = j_and(g, flags, cachebit);
411✔
3307

3308
   irgen_label_t *l_slow = irgen_alloc_label(g);
411✔
3309
   irgen_label_t *l_cont = irgen_alloc_label(g);
411✔
3310

3311
   j_cmp(g, JIT_CC_EQ, cacheflag, jit_value_from_int64(0));
411✔
3312
   j_jump(g, JIT_CC_T, l_slow);
411✔
3313

3314
   jit_value_t eventbit = jit_value_from_int64(SIG_F_EVENT_FLAG);
411✔
3315
   jit_value_t eventflag = j_and(g, flags, eventbit);
411✔
3316

3317
   jit_value_t shift = jit_value_from_int64(ilog2(SIG_F_EVENT_FLAG));
411✔
3318
   jit_value_t result = j_asr(g, eventflag, shift);
411✔
3319
   g->map[n.id] = result;
411✔
3320

3321
   j_jump(g, JIT_CC_NONE, l_cont);
411✔
3322

3323
   irgen_bind_label(g, l_slow);
411✔
3324

3325
   j_send(g, 0, shared);
411✔
3326
   j_send(g, 1, offset);
411✔
3327
   j_send(g, 2, count);
411✔
3328
   macro_exit(g, JIT_EXIT_TEST_EVENT);
411✔
3329

3330
   jit_value_t retval = j_recv(g, 0);
411✔
3331
   j_mov(g, jit_value_as_reg(result), retval);
411✔
3332

3333
   irgen_bind_label(g, l_cont);
411✔
3334
}
411✔
3335

3336
static void irgen_op_active(jit_irgen_t *g, mir_value_t n)
219✔
3337
{
3338
   jit_value_t shared = irgen_get_arg(g, n, 0);
219✔
3339
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
219✔
3340
   jit_value_t count  = irgen_get_arg(g, n, 1);
219✔
3341

3342
   j_send(g, 0, shared);
219✔
3343
   j_send(g, 1, offset);
219✔
3344
   j_send(g, 2, count);
219✔
3345
   macro_exit(g, JIT_EXIT_TEST_ACTIVE);
219✔
3346

3347
   g->map[n.id] = j_recv(g, 0);
219✔
3348
}
219✔
3349

3350
static void irgen_op_debug_out(jit_irgen_t *g, mir_value_t n)
×
3351
{
3352
   jit_value_t value = irgen_get_arg(g, n, 0);
×
3353

3354
   j_send(g, 0, value);
×
UNCOV
3355
   macro_exit(g, JIT_EXIT_DEBUG_OUT);
×
UNCOV
3356
}
×
3357

3358
static void irgen_op_last_event(jit_irgen_t *g, mir_value_t n)
33✔
3359
{
3360
   jit_value_t shared = irgen_get_arg(g, n, 0);
33✔
3361
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
33✔
3362

3363
   jit_value_t count;
33✔
3364
   if (mir_count_args(g->mu, n) > 1)
33✔
3365
      count = irgen_get_arg(g, n, 1);
9✔
3366
   else
3367
      count = jit_value_from_int64(1);
24✔
3368

3369
   j_send(g, 0, shared);
33✔
3370
   j_send(g, 1, offset);
33✔
3371
   j_send(g, 2, count);
33✔
3372
   macro_exit(g, JIT_EXIT_LAST_EVENT);
33✔
3373

3374
   g->map[n.id] = j_recv(g, 0);
33✔
3375
}
33✔
3376

3377
static void irgen_op_last_active(jit_irgen_t *g, mir_value_t n)
36✔
3378
{
3379
   jit_value_t shared = irgen_get_arg(g, n, 0);
36✔
3380
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
36✔
3381

3382
   jit_value_t count;
36✔
3383
   if (mir_count_args(g->mu, n) > 1)
36✔
3384
      count = irgen_get_arg(g, n, 1);
6✔
3385
   else
3386
      count = jit_value_from_int64(1);
30✔
3387

3388
   j_send(g, 0, shared);
36✔
3389
   j_send(g, 1, offset);
36✔
3390
   j_send(g, 2, count);
36✔
3391
   macro_exit(g, JIT_EXIT_LAST_ACTIVE);
36✔
3392

3393
   g->map[n.id] = j_recv(g, 0);
36✔
3394
}
36✔
3395

3396
static void irgen_op_driving(jit_irgen_t *g, mir_value_t n)
36✔
3397
{
3398
   jit_value_t shared = irgen_get_arg(g, n, 0);
36✔
3399
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
36✔
3400
   jit_value_t count  = irgen_get_arg(g, n, 1);
36✔
3401

3402
   j_send(g, 0, shared);
36✔
3403
   j_send(g, 1, offset);
36✔
3404
   j_send(g, 2, count);
36✔
3405

3406
   macro_exit(g, JIT_EXIT_DRIVING);
36✔
3407

3408
   g->map[n.id] = j_recv(g, 0);
36✔
3409
}
36✔
3410

3411
static void irgen_op_driving_value(jit_irgen_t *g, mir_value_t n)
138✔
3412
{
3413
   jit_value_t shared = irgen_get_arg(g, n, 0);
138✔
3414
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
138✔
3415

3416
   jit_value_t count;
138✔
3417
   if (mir_count_args(g->mu, n) > 1)
138✔
3418
      count = irgen_get_arg(g, n, 1);
33✔
3419
   else
3420
      count = jit_value_from_int64(1);
105✔
3421

3422
   j_send(g, 0, shared);
138✔
3423
   j_send(g, 1, offset);
138✔
3424
   j_send(g, 2, count);
138✔
3425

3426
   macro_exit(g, JIT_EXIT_DRIVING_VALUE);
138✔
3427

3428
   g->map[n.id] = j_recv(g, 0);
138✔
3429
}
138✔
3430

3431
static void irgen_op_cover_increment(jit_irgen_t *g, mir_value_t n)
2,296✔
3432
{
3433
   uint32_t tag = irgen_get_const(g, n, 0);
2,296✔
3434
   jit_value_t mem = jit_addr_from_cover_tag(tag);
2,296✔
3435

3436
   macro_sadd(g, JIT_SZ_32, mem, jit_value_from_int64(1));
2,296✔
3437
}
2,296✔
3438

3439
static void irgen_op_cover_toggle(jit_irgen_t *g, mir_value_t n)
381✔
3440
{
3441
   jit_value_t shared = irgen_get_arg(g, n, 0);
381✔
3442
   uint32_t tag = irgen_get_const(g, n, 1);
381✔
3443

3444
   j_send(g, 0, shared);
381✔
3445
   j_send(g, 1, jit_value_from_int64(tag));
381✔
3446
   macro_exit(g, JIT_EXIT_COVER_TOGGLE);
381✔
3447
}
381✔
3448

3449
static void irgen_op_cover_state(jit_irgen_t *g, mir_value_t n)
12✔
3450
{
3451
   jit_value_t shared = irgen_get_arg(g, n, 0);
12✔
3452
   jit_value_t low = irgen_get_arg(g, n, 1);
12✔
3453
   uint32_t tag = irgen_get_const(g, n, 2);
12✔
3454

3455
   j_send(g, 0, shared);
12✔
3456
   j_send(g, 1, low);
12✔
3457
   j_send(g, 2, jit_value_from_int64(tag));
12✔
3458
   macro_exit(g, JIT_EXIT_COVER_STATE);
12✔
3459
}
12✔
3460

3461
static void irgen_op_enter_state(jit_irgen_t *g, mir_value_t n)
768✔
3462
{
3463
   jit_value_t state = irgen_get_arg(g, n, 0);
768✔
3464

3465
   jit_value_t strong;
768✔
3466
   if (mir_count_args(g->mu, n) > 1)
768✔
3467
      strong = irgen_get_arg(g, n, 1);
18✔
3468
   else
3469
      strong = jit_value_from_int64(0);
750✔
3470

3471
   j_send(g, 0, state);
768✔
3472
   j_send(g, 1, strong);
768✔
3473
   macro_exit(g, JIT_EXIT_ENTER_STATE);
768✔
3474
}
768✔
3475

3476
static void irgen_op_function_trigger(jit_irgen_t *g, mir_value_t n)
212✔
3477
{
3478
   jit_handle_t handle = irgen_get_handle(g, n, 0);
212✔
3479

3480
   const int nargs = mir_count_args(g->mu, n);
212✔
3481

3482
   int nslots = 0;
212✔
3483
   for (int i = 1; i < nargs; i++) {
561✔
3484
      mir_type_t type = mir_get_type(g->mu, mir_get_arg(g->mu, n, i));
349✔
3485
      nslots += irgen_slots_for_type(g, type);
349✔
3486
   }
3487

3488
   j_send(g, 0, jit_value_from_handle(handle));
212✔
3489
   j_send(g, 1, jit_value_from_int64(nslots));
212✔
3490
   irgen_send_args(g, n, 2);
212✔
3491

3492
   macro_exit(g, JIT_EXIT_FUNCTION_TRIGGER);
212✔
3493

3494
   g->map[n.id] = j_recv(g, 0);
212✔
3495
}
212✔
3496

3497
static void irgen_op_or_trigger(jit_irgen_t *g, mir_value_t n)
33✔
3498
{
3499
   jit_value_t left = irgen_get_arg(g, n, 0);
33✔
3500
   jit_value_t right = irgen_get_arg(g, n, 1);
33✔
3501

3502
   j_send(g, 0, left);
33✔
3503
   j_send(g, 1, right);
33✔
3504

3505
   macro_exit(g, JIT_EXIT_OR_TRIGGER);
33✔
3506

3507
   g->map[n.id] = j_recv(g, 0);
33✔
3508
}
33✔
3509

3510
static void irgen_op_cmp_trigger(jit_irgen_t *g, mir_value_t n)
45✔
3511
{
3512
   jit_value_t shared = irgen_get_arg(g, n, 0);
45✔
3513
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
45✔
3514
   jit_value_t right = irgen_get_arg(g, n, 1);
45✔
3515

3516
   j_send(g, 0, shared);
45✔
3517
   j_send(g, 1, offset);
45✔
3518
   j_send(g, 2, right);
45✔
3519

3520
   macro_exit(g, JIT_EXIT_CMP_TRIGGER);
45✔
3521

3522
   g->map[n.id] = j_recv(g, 0);
45✔
3523
}
45✔
3524

3525
static void irgen_op_add_trigger(jit_irgen_t *g, mir_value_t n)
362✔
3526
{
3527
   jit_value_t trigger = irgen_get_arg(g, n, 0);
362✔
3528

3529
   j_send(g, 0, trigger);
362✔
3530
   macro_exit(g, JIT_EXIT_ADD_TRIGGER);
362✔
3531
}
362✔
3532

3533
static void irgen_op_port_conversion(jit_irgen_t *g, mir_value_t n)
279✔
3534
{
3535
   jit_value_t closure1 = irgen_get_arg(g, n, 0);
279✔
3536
   jit_value_t context1 = jit_value_from_reg(jit_value_as_reg(closure1) + 1);
279✔
3537

3538
   jit_value_t closure2, context2;
279✔
3539
   if (mir_count_args(g->mu, n) > 1) {
279✔
3540
      closure2 = irgen_get_arg(g, n, 1);
18✔
3541
      context2 = jit_value_from_reg(jit_value_as_reg(closure2) + 1);
18✔
3542
   }
3543
   else {
3544
      closure2 = jit_value_from_handle(JIT_HANDLE_INVALID);
261✔
3545
      context2 = jit_value_from_int64(0);
261✔
3546
   }
3547

3548
   j_send(g, 0, closure1);
279✔
3549
   j_send(g, 1, context1);
279✔
3550
   j_send(g, 2, closure2);
279✔
3551
   j_send(g, 3, context2);
279✔
3552
   macro_exit(g, JIT_EXIT_PORT_CONVERSION);
279✔
3553

3554
   g->map[n.id] = j_recv(g, 0);
279✔
3555
}
279✔
3556

3557
static void irgen_op_convert_in(jit_irgen_t *g, mir_value_t n)
354✔
3558
{
3559
   jit_value_t conv   = irgen_get_arg(g, n, 0);
354✔
3560
   jit_value_t shared = irgen_get_arg(g, n, 1);
354✔
3561
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
354✔
3562
   jit_value_t count  = irgen_get_arg(g, n, 2);
354✔
3563

3564
   j_send(g, 0, conv);
354✔
3565
   j_send(g, 1, shared);
354✔
3566
   j_send(g, 2, offset);
354✔
3567
   j_send(g, 3, count);
354✔
3568
   macro_exit(g, JIT_EXIT_CONVERT_IN);
354✔
3569
}
354✔
3570

3571
static void irgen_op_convert_out(jit_irgen_t *g, mir_value_t n)
396✔
3572
{
3573
   jit_value_t conv   = irgen_get_arg(g, n, 0);
396✔
3574
   jit_value_t shared = irgen_get_arg(g, n, 1);
396✔
3575
   jit_value_t offset = jit_value_from_reg(jit_value_as_reg(shared) + 1);
396✔
3576
   jit_value_t count  = irgen_get_arg(g, n, 2);
396✔
3577

3578
   j_send(g, 0, conv);
396✔
3579
   j_send(g, 1, shared);
396✔
3580
   j_send(g, 2, offset);
396✔
3581
   j_send(g, 3, count);
396✔
3582
   macro_exit(g, JIT_EXIT_CONVERT_OUT);
396✔
3583
}
396✔
3584

3585
static void irgen_op_bind_foreign(jit_irgen_t *g, mir_value_t n)
259✔
3586
{
3587
   jit_value_t spec   = irgen_get_arg(g, n, 0);
259✔
3588
   jit_value_t length = irgen_get_arg(g, n, 1);
259✔
3589

3590
   jit_value_t locus;
259✔
3591
   if (mir_count_args(g->mu, n) > 2)
259✔
3592
      locus = irgen_get_arg(g, n, 2);
137✔
3593
   else
3594
      locus = jit_value_from_int64(0);
122✔
3595

3596
   j_send(g, 0, spec);
259✔
3597
   j_send(g, 1, length);
259✔
3598
   j_send(g, 2, locus);
259✔
3599
   macro_exit(g, JIT_EXIT_BIND_FOREIGN);
259✔
3600

3601
   int pslot = 0;
259✔
3602
   if (mir_is_null(mir_get_result(g->mu)))
259✔
3603
      j_send(g, pslot++, jit_value_from_int64(0));    // Procedure state
122✔
3604

3605
   const int nparams = mir_count_params(g->mu);
259✔
3606
   for (int i = 0; i < nparams; i++) {
878✔
3607
      mir_value_t p = mir_get_param(g->mu, i);
619✔
3608
      const int slots = irgen_slots_for_type(g, mir_get_type(g->mu, p));
619✔
3609
      if (unlikely(pslot + slots >= JIT_MAX_ARGS))
619✔
UNCOV
3610
         fatal("foreign subprogram %s requires more than the maximum supported "
×
UNCOV
3611
               "%d arguments", istr(mir_get_name(g->mu, MIR_NULL_VALUE)),
×
3612
               JIT_MAX_ARGS);
3613

3614
      jit_value_t r = irgen_get_value(g, p);
619✔
3615
      j_send(g, pslot++, r);
619✔
3616
      for (int j = 1; j < slots; j++)
719✔
3617
         j_send(g, pslot++, jit_value_from_reg(jit_value_as_reg(r) + j));
100✔
3618
   }
3619

3620
   macro_reexec(g);
259✔
3621
}
259✔
3622

3623
static void irgen_op_instance_name(jit_irgen_t *g, mir_value_t n)
812✔
3624
{
3625
   irgen_send_args(g, n, 0);
812✔
3626

3627
   macro_exit(g, JIT_EXIT_INSTANCE_NAME);
812✔
3628

3629
   const int slots = irgen_slots_for_type(g, mir_get_type(g->mu, n));
812✔
3630
   g->map[n.id] = j_recv(g, 0);
812✔
3631
   for (int i = 1; i < slots; i++)
2,436✔
3632
      j_recv(g, i);
1,624✔
3633
}
812✔
3634

3635
static void irgen_op_bind_external(jit_irgen_t *g, mir_value_t n)
194✔
3636
{
3637
   jit_value_t locus = irgen_get_arg(g, n, 0);
194✔
3638
   jit_handle_t handle = irgen_get_handle(g, n, 1);
194✔
3639

3640
   j_send(g, 0, locus);
194✔
3641
   j_send(g, 1, jit_value_from_handle(handle));
194✔
3642
   macro_exit(g, JIT_EXIT_BIND_EXTERNAL);
194✔
3643

3644
   g->map[n.id] = j_recv(g, 0);
194✔
3645
}
194✔
3646

3647
static void irgen_block(jit_irgen_t *g, mir_block_t block)
134,882✔
3648
{
3649
   irgen_bind_label(g, g->blocks[block.id]);
134,882✔
3650

3651
   g->flags = MIR_NULL_VALUE;
134,882✔
3652
   g->curblock = block;
134,882✔
3653

3654
   const int nops = mir_count_nodes(g->mu, block);
134,882✔
3655
   for (int i = 0; i < nops; i++) {
1,229,641✔
3656
      mir_value_t n = mir_get_node(g->mu, block, i);
1,094,759✔
3657

3658
      const mir_op_t op = mir_get_op(g->mu, n);
1,094,759✔
3659
      if (op == MIR_OP_COMMENT)
1,094,759✔
UNCOV
3660
         continue;
×
3661

3662
#ifdef DEBUG
3663
      mir_set_cursor(g->mu, block, i);
1,094,759✔
3664
      irgen_emit_debuginfo(g, n);
1,094,759✔
3665
#endif
3666

3667
      switch (op) {
1,094,759✔
3668
      case MIR_OP_CONST:
6,763✔
3669
         irgen_op_const(g, n);
6,763✔
3670
         break;
6,763✔
3671
      case MIR_OP_CONST_REAL:
20,897✔
3672
         irgen_op_const_real(g, n);
20,897✔
3673
         break;
20,897✔
3674
      case MIR_OP_CONST_ARRAY:
21,165✔
3675
         irgen_op_const_array(g, n);
21,165✔
3676
         break;
21,165✔
3677
      case MIR_OP_CONST_REP:
279✔
3678
         irgen_op_const_rep(g, n);
279✔
3679
         break;
279✔
3680
      case MIR_OP_CONST_RECORD:
2,138✔
3681
         irgen_op_const_record(g, n);
2,138✔
3682
         break;
2,138✔
3683
      case MIR_OP_ADDRESS_OF:
22,584✔
3684
         irgen_op_address_of(g, n);
22,584✔
3685
         break;
22,584✔
3686
      case MIR_OP_LOCUS:
65,860✔
3687
         irgen_op_locus(g, n);
65,860✔
3688
         break;
65,860✔
3689
      case MIR_OP_TRAP_ADD:
1,913✔
3690
         irgen_op_trap_add(g, n);
1,913✔
3691
         break;
1,913✔
3692
      case MIR_OP_NOT:
2,646✔
3693
         irgen_op_not(g, n);
2,646✔
3694
         break;
2,646✔
3695
      case MIR_OP_AND:
4,412✔
3696
         irgen_op_and(g, n);
4,412✔
3697
         break;
4,412✔
3698
      case MIR_OP_NAND:
62✔
3699
         irgen_op_nand(g, n);
62✔
3700
         break;
62✔
3701
      case MIR_OP_OR:
1,788✔
3702
         irgen_op_or(g, n);
1,788✔
3703
         break;
1,788✔
3704
      case MIR_OP_NOR:
62✔
3705
         irgen_op_nor(g, n);
62✔
3706
         break;
62✔
3707
      case MIR_OP_XOR:
104✔
3708
         irgen_op_xor(g, n);
104✔
3709
         break;
104✔
3710
      case MIR_OP_XNOR:
64✔
3711
         irgen_op_xnor(g, n);
64✔
3712
         break;
64✔
3713
      case MIR_OP_ADD:
12,928✔
3714
         irgen_op_add(g, n);
12,928✔
3715
         break;
12,928✔
3716
      case MIR_OP_TRAP_MUL:
325✔
3717
         irgen_op_trap_mul(g, n);
325✔
3718
         break;
325✔
3719
      case MIR_OP_MUL:
2,091✔
3720
         irgen_op_mul(g, n);
2,091✔
3721
         break;
2,091✔
3722
      case MIR_OP_DIV:
885✔
3723
         irgen_op_div(g, n);
885✔
3724
         break;
885✔
3725
      case MIR_OP_EXP:
72✔
3726
         irgen_op_exp(g, n);
72✔
3727
         break;
72✔
3728
      case MIR_OP_TRAP_EXP:
531✔
3729
         irgen_op_trap_exp(g, n);
531✔
3730
         break;
531✔
3731
      case MIR_OP_SUB:
17,591✔
3732
         irgen_op_sub(g, n);
17,591✔
3733
         break;
17,591✔
3734
      case MIR_OP_TRAP_SUB:
2,039✔
3735
         irgen_op_trap_sub(g, n);
2,039✔
3736
         break;
2,039✔
3737
      case MIR_OP_NEG:
7,480✔
3738
         irgen_op_neg(g, n);
7,480✔
3739
         break;
7,480✔
3740
      case MIR_OP_TRAP_NEG:
555✔
3741
         irgen_op_trap_neg(g, n);
555✔
3742
         break;
555✔
3743
      case MIR_OP_ABS:
233✔
3744
         irgen_op_abs(g, n);
233✔
3745
         break;
233✔
3746
      case MIR_OP_MOD:
151✔
3747
         irgen_op_mod(g, n);
151✔
3748
         break;
151✔
3749
      case MIR_OP_REM:
94✔
3750
         irgen_op_rem(g, n);
94✔
3751
         break;
94✔
3752
      case MIR_OP_CMP:
33,541✔
3753
         irgen_op_cmp(g, n);
33,541✔
3754
         break;
33,541✔
3755
      case MIR_OP_RETURN:
51,222✔
3756
         irgen_op_return(g, n);
51,222✔
3757
         break;
51,222✔
3758
      case MIR_OP_STORE:
71,915✔
3759
         irgen_op_store(g, n);
71,915✔
3760
         break;
71,915✔
3761
      case MIR_OP_LOAD:
117,060✔
3762
         irgen_op_load(g, n);
117,060✔
3763
         break;
117,060✔
3764
      case MIR_OP_WRAP:
28,989✔
3765
         irgen_op_wrap(g, n);
28,989✔
3766
         break;
28,989✔
3767
      case MIR_OP_UARRAY_LEFT:
16,600✔
3768
         irgen_op_uarray_left(g, n);
16,600✔
3769
         break;
16,600✔
3770
      case MIR_OP_UARRAY_RIGHT:
14,520✔
3771
         irgen_op_uarray_right(g, n);
14,520✔
3772
         break;
14,520✔
3773
      case MIR_OP_UARRAY_DIR:
16,562✔
3774
         irgen_op_uarray_dir(g, n);
16,562✔
3775
         break;
16,562✔
3776
      case MIR_OP_UARRAY_LEN:
20,668✔
3777
         irgen_op_uarray_len(g, n);
20,668✔
3778
         break;
20,668✔
3779
      case MIR_OP_UNWRAP:
24,249✔
3780
         irgen_op_unwrap(g, n);
24,249✔
3781
         break;
24,249✔
3782
      case MIR_OP_CAST:
45,752✔
3783
         irgen_op_cast(g, n);
45,752✔
3784
         break;
45,752✔
3785
      case MIR_OP_RANGE_NULL:
4,610✔
3786
         irgen_op_range_null(g, n);
4,610✔
3787
         break;
4,610✔
3788
      case MIR_OP_RANGE_LENGTH:
6,132✔
3789
         irgen_op_range_length(g, n);
6,132✔
3790
         break;
6,132✔
3791
      case MIR_OP_COND:
32,928✔
3792
         irgen_op_cond(g, n);
32,928✔
3793
         break;
32,928✔
3794
      case MIR_OP_SELECT:
12,307✔
3795
         irgen_op_select(g, n);
12,307✔
3796
         break;
12,307✔
3797
      case MIR_OP_JUMP:
35,153✔
3798
         irgen_op_jump(g, n);
35,153✔
3799
         break;
35,153✔
3800
      case MIR_OP_ARRAY_REF:
32,376✔
3801
         irgen_op_array_ref(g, n);
32,376✔
3802
         break;
32,376✔
3803
      case MIR_OP_CONTEXT_UPREF:
8,648✔
3804
         irgen_op_context_upref(g, n);
8,648✔
3805
         break;
8,648✔
3806
      case MIR_OP_FCALL:
35,798✔
3807
         irgen_op_fcall(g, n);
35,798✔
3808
         break;
35,798✔
3809
      case MIR_OP_PCALL:
875✔
3810
         irgen_op_pcall(g, n);
875✔
3811
         break;
875✔
3812
      case MIR_OP_RESUME:
875✔
3813
         irgen_op_resume(g, n);
875✔
3814
         break;
875✔
3815
      case MIR_OP_SYSCALL:
423✔
3816
         irgen_op_syscall(g, n);
423✔
3817
         break;
423✔
3818
      case MIR_OP_WAIT:
13,488✔
3819
         irgen_op_wait(g, n);
13,488✔
3820
         break;
13,488✔
3821
      case MIR_OP_COPY:
15,649✔
3822
         irgen_op_copy(g, n);
15,649✔
3823
         break;
15,649✔
3824
      case MIR_OP_SET:
5,549✔
3825
         irgen_op_set(g, n);
5,549✔
3826
         break;
5,549✔
3827
      case MIR_OP_VAR_UPREF:
45,545✔
3828
         irgen_op_var_upref(g, n);
45,545✔
3829
         break;
45,545✔
3830
      case MIR_OP_INDEX_CHECK:
11,085✔
3831
         irgen_op_index_check(g, n);
11,085✔
3832
         break;
11,085✔
3833
      case MIR_OP_RANGE_CHECK:
3,019✔
3834
         irgen_op_range_check(g, n);
3,019✔
3835
         break;
3,019✔
3836
      case MIR_OP_PACKAGE_INIT:
17,595✔
3837
         irgen_op_package_init(g, n);
17,595✔
3838
         break;
17,595✔
3839
      case MIR_OP_LINK_PACKAGE:
11,397✔
3840
         irgen_op_link_package(g, n);
11,397✔
3841
         break;
11,397✔
3842
      case MIR_OP_LINK_VAR:
2,522✔
3843
         irgen_op_link_var(g, n);
2,522✔
3844
         break;
2,522✔
3845
      case MIR_OP_RECORD_REF:
37,502✔
3846
         irgen_op_record_ref(g, n);
37,502✔
3847
         break;
37,502✔
3848
      case MIR_OP_NULL:
2,712✔
3849
         irgen_op_null(g, n);
2,712✔
3850
         break;
2,712✔
3851
      case MIR_OP_NEW:
410✔
3852
         irgen_op_new(g, n);
410✔
3853
         break;
410✔
3854
      case MIR_OP_ALLOC:
7,239✔
3855
         irgen_op_alloc(g, n);
7,239✔
3856
         break;
7,239✔
3857
      case MIR_OP_ALL:
1,507✔
3858
         irgen_op_all(g, n);
1,507✔
3859
         break;
1,507✔
3860
      case MIR_OP_EXPONENT_CHECK:
513✔
3861
         irgen_op_exponent_check(g, n);
513✔
3862
         break;
513✔
3863
      case MIR_OP_NULL_CHECK:
1,097✔
3864
         irgen_op_null_check(g, n);
1,097✔
3865
         break;
1,097✔
3866
      case MIR_OP_ZERO_CHECK:
100✔
3867
         irgen_op_zero_check(g, n);
100✔
3868
         break;
100✔
3869
      case MIR_OP_LENGTH_CHECK:
6,744✔
3870
         irgen_op_length_check(g, n);
6,744✔
3871
         break;
6,744✔
3872
      case MIR_OP_CLOSURE:
1,355✔
3873
         irgen_op_closure(g, n);
1,355✔
3874
         break;
1,355✔
3875
      case MIR_OP_RESOLUTION_WRAPPER:
983✔
3876
         irgen_op_resolution_wrapper(g, n);
983✔
3877
         break;
983✔
3878
      case MIR_OP_INIT_SIGNAL:
16,184✔
3879
         irgen_op_init_signal(g, n);
16,184✔
3880
         break;
16,184✔
3881
      case MIR_OP_IMPLICIT_SIGNAL:
75✔
3882
         irgen_op_implicit_signal(g, n);
75✔
3883
         break;
75✔
3884
      case MIR_OP_ALIAS_SIGNAL:
4,232✔
3885
         irgen_op_alias_signal(g, n);
4,232✔
3886
         break;
4,232✔
3887
      case MIR_OP_MAP_SIGNAL:
5,322✔
3888
         irgen_op_map_signal(g, n);
5,322✔
3889
         break;
5,322✔
3890
      case MIR_OP_MAP_CONST:
219✔
3891
         irgen_op_map_const(g, n);
219✔
3892
         break;
219✔
3893
      case MIR_OP_MAP_IMPLICIT:
57✔
3894
         irgen_op_map_implicit(g, n);
57✔
3895
         break;
57✔
3896
      case MIR_OP_RESOLVE_SIGNAL:
3,451✔
3897
         irgen_op_resolve_signal(g, n);
3,451✔
3898
         break;
3,451✔
3899
      case MIR_OP_UNREACHABLE:
595✔
3900
         irgen_op_unreachable(g, n);
595✔
3901
         break;
595✔
3902
      case MIR_OP_REPORT:
2,244✔
3903
         irgen_op_report(g, n);
2,244✔
3904
         break;
2,244✔
3905
      case MIR_OP_ASSERT:
14,001✔
3906
         irgen_op_assert(g, n);
14,001✔
3907
         break;
14,001✔
3908
      case MIR_OP_CASE:
621✔
3909
         irgen_op_case(g, n);
621✔
3910
         break;
621✔
3911
      case MIR_OP_PROTECTED_INIT:
162✔
3912
         irgen_op_protected_init(g, n);
162✔
3913
         break;
162✔
3914
      case MIR_OP_REFLECT_VALUE:
45✔
3915
         irgen_op_reflect_value(g, n);
45✔
3916
         break;
45✔
3917
      case MIR_OP_REFLECT_SUBTYPE:
42✔
3918
         irgen_op_reflect_subtype(g, n);
42✔
3919
         break;
42✔
3920
      case MIR_OP_PROCESS_INIT:
112✔
3921
         irgen_op_process_init(g, n);
112✔
3922
         break;
112✔
3923
      case MIR_OP_FILE_OPEN:
261✔
3924
         irgen_op_file_open(g, n);
261✔
3925
         break;
261✔
3926
      case MIR_OP_FILE_READ:
75✔
3927
         irgen_op_file_read(g, n);
75✔
3928
         break;
75✔
3929
      case MIR_OP_FILE_WRITE:
122✔
3930
         irgen_op_file_write(g, n);
122✔
3931
         break;
122✔
3932
      case MIR_OP_PACKAGE_SCOPE:
45✔
3933
         irgen_op_package_scope(g, n);
45✔
3934
         break;
45✔
3935
      case MIR_OP_ARRAY_SCOPE:
632✔
3936
         irgen_op_array_scope(g, n);
632✔
3937
         break;
632✔
3938
      case MIR_OP_RECORD_SCOPE:
1,606✔
3939
         irgen_op_record_scope(g, n);
1,606✔
3940
         break;
1,606✔
3941
      case MIR_OP_POP_SCOPE:
2,283✔
3942
         irgen_op_pop_scope(g, n);
2,283✔
3943
         break;
2,283✔
3944
      case MIR_OP_DRIVE_SIGNAL:
9,197✔
3945
         irgen_op_drive_signal(g, n);
9,197✔
3946
         break;
9,197✔
3947
      case MIR_OP_TRANSFER_SIGNAL:
1,160✔
3948
         irgen_op_transfer_signal(g, n);
1,160✔
3949
         break;
1,160✔
3950
      case MIR_OP_RESOLVED:
14,108✔
3951
         irgen_op_resolved(g, n);
14,108✔
3952
         break;
14,108✔
3953
      case MIR_OP_LAST_VALUE:
90✔
3954
         irgen_op_last_value(g, n);
90✔
3955
         break;
90✔
3956
      case MIR_OP_SCHED_WAVEFORM:
10,611✔
3957
         irgen_op_sched_waveform(g, n);
10,611✔
3958
         break;
10,611✔
3959
      case MIR_OP_DISCONNECT:
24✔
3960
         irgen_op_disconnect(g, n);
24✔
3961
         break;
24✔
3962
      case MIR_OP_FORCE:
60✔
3963
         irgen_op_force(g, n);
60✔
3964
         break;
60✔
3965
      case MIR_OP_RELEASE:
30✔
3966
         irgen_op_release(g, n);
30✔
3967
         break;
30✔
3968
      case MIR_OP_DEPOSIT_SIGNAL:
177✔
3969
         irgen_op_deposit_signal(g, n);
177✔
3970
         break;
177✔
3971
      case MIR_OP_PUT_CONVERSION:
402✔
3972
         irgen_op_put_conversion(g, n);
402✔
3973
         break;
402✔
3974
      case MIR_OP_EVENT:
411✔
3975
         irgen_op_event(g, n);
411✔
3976
         break;
411✔
3977
      case MIR_OP_ACTIVE:
219✔
3978
         irgen_op_active(g, n);
219✔
3979
         break;
219✔
3980
      case MIR_OP_SCHED_EVENT:
5,813✔
3981
         irgen_op_sched_event(g, n);
5,813✔
3982
         break;
5,813✔
3983
      case MIR_OP_CLEAR_EVENT:
499✔
3984
         irgen_op_clear_event(g, n);
499✔
3985
         break;
499✔
3986
      case MIR_OP_DEBUG_OUT:
×
UNCOV
3987
         irgen_op_debug_out(g, n);
×
UNCOV
3988
         break;
×
3989
      case MIR_OP_LAST_EVENT:
33✔
3990
         irgen_op_last_event(g, n);
33✔
3991
         break;
33✔
3992
      case MIR_OP_LAST_ACTIVE:
36✔
3993
         irgen_op_last_active(g, n);
36✔
3994
         break;
36✔
3995
      case MIR_OP_DRIVING:
36✔
3996
         irgen_op_driving(g, n);
36✔
3997
         break;
36✔
3998
      case MIR_OP_DRIVING_VALUE:
138✔
3999
         irgen_op_driving_value(g, n);
138✔
4000
         break;
138✔
4001
      case MIR_OP_COVER_STMT:
2,296✔
4002
      case MIR_OP_COVER_BRANCH:
4003
      case MIR_OP_COVER_EXPR:
4004
         irgen_op_cover_increment(g, n);
2,296✔
4005
         break;
2,296✔
4006
      case MIR_OP_COVER_TOGGLE:
381✔
4007
         irgen_op_cover_toggle(g, n);
381✔
4008
         break;
381✔
4009
      case MIR_OP_COVER_STATE:
12✔
4010
         irgen_op_cover_state(g, n);
12✔
4011
         break;
12✔
4012
      case MIR_OP_ENTER_STATE:
768✔
4013
         irgen_op_enter_state(g, n);
768✔
4014
         break;
768✔
4015
      case MIR_OP_FUNCTION_TRIGGER:
212✔
4016
         irgen_op_function_trigger(g, n);
212✔
4017
         break;
212✔
4018
      case MIR_OP_OR_TRIGGER:
33✔
4019
         irgen_op_or_trigger(g, n);
33✔
4020
         break;
33✔
4021
      case MIR_OP_CMP_TRIGGER:
45✔
4022
         irgen_op_cmp_trigger(g, n);
45✔
4023
         break;
45✔
4024
      case MIR_OP_ADD_TRIGGER:
362✔
4025
         irgen_op_add_trigger(g, n);
362✔
4026
         break;
362✔
4027
      case MIR_OP_PORT_CONVERSION:
279✔
4028
         irgen_op_port_conversion(g, n);
279✔
4029
         break;
279✔
4030
      case MIR_OP_CONVERT_IN:
354✔
4031
         irgen_op_convert_in(g, n);
354✔
4032
         break;
354✔
4033
      case MIR_OP_CONVERT_OUT:
396✔
4034
         irgen_op_convert_out(g, n);
396✔
4035
         break;
396✔
4036
      case MIR_OP_BIND_FOREIGN:
259✔
4037
         irgen_op_bind_foreign(g, n);
259✔
4038
         break;
259✔
4039
      case MIR_OP_INSTANCE_NAME:
812✔
4040
         irgen_op_instance_name(g, n);
812✔
4041
         break;
812✔
4042
      case MIR_OP_BIND_EXTERNAL:
194✔
4043
         irgen_op_bind_external(g, n);
194✔
4044
         break;
194✔
UNCOV
4045
      default:
×
UNCOV
4046
         DEBUG_ONLY(mir_dump(g->mu));
×
4047
         fatal_trace("cannot generate JIT IR for MIR op %s", mir_op_string(op));
4048
      }
4049
   }
4050
}
134,882✔
4051

4052
static void irgen_locals(jit_irgen_t *g)
42,732✔
4053
{
4054
   const int nvars = mir_count_vars(g->mu);
42,732✔
4055
   g->vars = xmalloc_array(nvars, sizeof(jit_value_t));
42,732✔
4056

4057
   bool on_stack;
42,732✔
4058
   const mir_unit_kind_t kind = mir_get_kind(g->mu);
42,732✔
4059
   switch (kind) {
42,732✔
4060
   case MIR_UNIT_PROCESS:
9,205✔
4061
   case MIR_UNIT_PROPERTY:
4062
      on_stack = g->stateless;
9,205✔
4063
      break;
9,205✔
4064
   case MIR_UNIT_INSTANCE:
4065
   case MIR_UNIT_PROCEDURE:
4066
   case MIR_UNIT_PACKAGE:
4067
   case MIR_UNIT_PROTECTED:
4068
   case MIR_UNIT_PLACEHOLDER:
4069
      on_stack = false;
4070
      break;
4071
   default:
21,932✔
4072
      on_stack = !g->needs_context;
21,932✔
4073
      break;
21,932✔
4074
   }
4075

4076
   if (on_stack) {
31,137✔
4077
      // Local variables on stack
4078
      for (int i = 0; i < nvars; i++) {
41,013✔
4079
         mir_value_t var = mir_get_var(g->mu, i);
13,596✔
4080
         mir_type_t type = mir_get_var_type(g->mu, var);
13,596✔
4081
         const int sz = irgen_size_bytes(g, type);
13,596✔
4082
         if ((mir_get_var_flags(g->mu, var) & MIR_VAR_HEAP)
13,596✔
4083
             || sz > MAX_STACK_ALLOC) {
12,851✔
4084
            g->vars[i] = macro_lalloc(g, jit_value_from_int64(sz));
745✔
4085
            g->used_tlab = true;
745✔
4086
         }
4087
         else
4088
            g->vars[i] = macro_salloc(g, sz);
12,851✔
4089
      }
4090
   }
4091
   else {
4092
      // Local variables on heap
4093
      size_t sz = 0;
15,315✔
4094
      sz += sizeof(void *);   // Context parameter
15,315✔
4095
      if (kind == MIR_UNIT_PROCESS || kind == MIR_UNIT_PROCEDURE) {
15,315✔
4096
         sz += sizeof(void *);   // Suspended procedure state
3,856✔
4097
         sz += sizeof(int32_t);  // State number
3,856✔
4098
      }
4099

4100
      link_tab_t *linktab = xmalloc_array(nvars, sizeof(link_tab_t));
15,315✔
4101

4102
      for (int i = 0; i < nvars; i++) {
50,406✔
4103
         mir_value_t var = mir_get_var(g->mu, i);
35,091✔
4104
         mir_type_t type = mir_get_var_type(g->mu, var);
35,091✔
4105
         const int align = irgen_align_of(g, type);
35,091✔
4106
         sz = ALIGN_UP(sz, align);
35,091✔
4107
         linktab[i].name = mir_get_name(g->mu, var);
35,091✔
4108
         linktab[i].offset = sz;
35,091✔
4109
         sz += irgen_size_bytes(g, type);
35,091✔
4110
      }
4111

4112
      jit_value_t mem;
15,315✔
4113
      if (kind == MIR_UNIT_PROTECTED) {
15,315✔
4114
         // Protected types must always be allocated on the global heap
4115
         // as the result may be stored in an access
4116
         mem = macro_galloc(g, jit_value_from_int64(sz));
172✔
4117
      }
4118
      else {
4119
         mem = macro_lalloc(g, jit_value_from_int64(sz));
15,143✔
4120
         g->used_tlab = true;
15,143✔
4121
      }
4122

4123
      if (g->statereg.kind != JIT_VALUE_INVALID) {
15,315✔
4124
         // A null state was passed in by the caller
4125
         j_mov(g, jit_value_as_reg(g->statereg), mem);
3,883✔
4126
      }
4127
      else
4128
         g->statereg = mem;
11,432✔
4129

4130
      for (int i = 0; i < nvars; i++)
50,406✔
4131
         g->vars[i] = jit_addr_from_value(g->statereg, linktab[i].offset);
35,091✔
4132

4133
      // Publish the variable offset table early to handle circular references
4134
      // This may be read by another thread while in the COMPILING state
4135
      g->func->nvars = nvars;
15,315✔
4136
      store_release(&(g->func->linktab), linktab);
15,315✔
4137
   }
4138
}
42,732✔
4139

4140
static void irgen_params(jit_irgen_t *g, int first)
11,274✔
4141
{
4142
   // We never need more than the first few argument types
4143
   ffi_type_t types[7];
11,274✔
4144
   types[first] = FFI_POINTER;
11,274✔
4145
   types[0] = FFI_VOID;
11,274✔
4146

4147
   jit_value_t spill = { .kind = JIT_VALUE_INVALID };
11,274✔
4148
   int32_t spilloff = 0;
11,274✔
4149

4150
   const int nparams = mir_count_params(g->mu);
11,274✔
4151
   g->params = xmalloc_array(nparams, sizeof(jit_value_t));
11,274✔
4152

4153
   for (int i = 0, pslot = first; i < nparams; i++) {
40,589✔
4154
      mir_value_t p = mir_get_param(g->mu, i);
29,315✔
4155
      mir_type_t type = mir_get_type(g->mu, p);
29,315✔
4156
      int slots = irgen_slots_for_type(g, type);
29,315✔
4157

4158
      if (pslot + slots >= JIT_MAX_ARGS - 1) {
29,315✔
4159
         // Large number of arguments spill to the heap
4160
         if (spill.kind == JIT_VALUE_INVALID) {
18✔
4161
            spill = j_recv(g, JIT_MAX_ARGS - 1);
3✔
4162
            pslot = JIT_MAX_ARGS;
3✔
4163
         }
4164

4165
         jit_value_t ptr = jit_addr_from_value(spill, spilloff);
18✔
4166
         g->params[p.id] = j_load(g, JIT_SZ_64, ptr);
18✔
4167
         spilloff += sizeof(jit_scalar_t);
18✔
4168

4169
         for (int i = 1; i < slots; i++, spilloff += sizeof(jit_scalar_t)) {
75✔
4170
            jit_value_t ptr = jit_addr_from_value(spill, spilloff);
57✔
4171
            j_load(g, JIT_SZ_64, ptr);   // Must be contiguous registers
57✔
4172
         }
4173
      }
4174
      else {
4175
         g->params[p.id] = j_recv(g, pslot++);
29,297✔
4176
         for (int i = 1; i < slots; i++)
47,857✔
4177
            j_recv(g, pslot++);   // Must be contiguous registers
18,560✔
4178
      }
4179

4180
      if (i + first + 1 < ARRAY_LEN(types))
29,315✔
4181
         types[i + first + 1] = irgen_ffi_type(g, type);
28,975✔
4182
   }
4183

4184
   mir_unit_kind_t kind = mir_get_kind(g->mu);
11,274✔
4185
   if (kind == MIR_UNIT_FUNCTION || kind == MIR_UNIT_THUNK) {
11,274✔
4186
      mir_type_t rtype = mir_get_result(g->mu);
10,646✔
4187
      if (!mir_is_null(rtype))
10,646✔
4188
         types[0] = irgen_ffi_type(g, rtype);
9,261✔
4189
   }
4190

4191
   const int ntypes = MIN(ARRAY_LEN(types), first + nparams + 1);
11,274✔
4192
   g->func->spec = ffi_spec_new(types, ntypes);
11,274✔
4193
}
11,274✔
4194

4195
static void irgen_jump_table(jit_irgen_t *g)
3,856✔
4196
{
4197
   g->statereg = j_recv(g, 0);
3,856✔
4198

4199
   irgen_label_t *cont = irgen_alloc_label(g);
3,856✔
4200
   j_cmp(g, JIT_CC_EQ, g->statereg, jit_value_from_int64(0));
3,856✔
4201
   j_jump(g, JIT_CC_T, cont);
3,856✔
4202

4203
   jit_value_t state_ptr = irgen_state_ptr(g);
3,856✔
4204
   jit_value_t state = j_load(g, JIT_SZ_32, state_ptr);
3,856✔
4205
   jit_reg_t state_reg = jit_value_as_reg(state);
3,856✔
4206

4207
   const bool is_process = (mir_get_kind(g->mu) == MIR_UNIT_PROCESS);
3,856✔
4208
   const int nblocks = mir_count_blocks(g->mu);
3,856✔
4209

4210
   bit_mask_t have;
3,856✔
4211
   mask_init(&have, nblocks);
3,856✔
4212

4213
   for (int i = 0; i < nblocks; i++) {
32,498✔
4214
      mir_block_t b = mir_get_block(g->mu, i);
28,642✔
4215

4216
      const int num_nodes = mir_count_nodes(g->mu, b);
28,642✔
4217
      if (num_nodes == 0)
28,642✔
UNCOV
4218
         continue;
×
4219

4220
      mir_value_t last = mir_get_node(g->mu, b, num_nodes - 1);
28,642✔
4221

4222
      mir_block_t target = MIR_NULL_BLOCK;
28,642✔
4223
      const mir_op_t last_op = mir_get_op(g->mu, last);
28,642✔
4224

4225
      if (last_op == MIR_OP_WAIT || last_op == MIR_OP_PCALL)
28,642✔
4226
         target = mir_cast_block(mir_get_arg(g->mu, last, 0));
10,234✔
4227
      else if (is_process && last_op == MIR_OP_RETURN)
18,408✔
4228
         target = mir_get_block(g->mu, 1);
3,664✔
4229

4230
      if (mir_is_null(target) || mask_test(&have, target.id))
28,642✔
4231
         continue;
15,090✔
4232

4233
      macro_case(g, state_reg, jit_value_from_int64(target.id),
13,552✔
4234
                 g->blocks[target.id]);
13,552✔
4235

4236
      mask_set(&have, target.id);
28,642✔
4237
   }
4238

4239
   DEBUG_ONLY(j_trap(g));
3,856✔
4240

4241
   irgen_bind_label(g, cont);
3,856✔
4242
   mask_free(&have);
3,856✔
4243
}
3,856✔
4244

4245
static void irgen_analyse(jit_irgen_t *g)
42,732✔
4246
{
4247
   // A process is stateless if it has no non-temporary variables and
4248
   // all wait statements resume at the initial block
4249
   const mir_unit_kind_t kind = mir_get_kind(g->mu);
42,732✔
4250
   g->stateless = (kind == MIR_UNIT_PROCESS || kind == MIR_UNIT_PROPERTY);
42,732✔
4251

4252
   const int nvars = mir_count_vars(g->mu);
42,732✔
4253
   for (int i = 0; i < nvars; i++) {
46,560✔
4254
      mir_value_t var = mir_get_var(g->mu, i);
17,879✔
4255
      if (!(mir_get_var_flags(g->mu, var) & MIR_VAR_TEMP)) {
17,879✔
4256
         g->stateless = false;
14,051✔
4257
         break;
14,051✔
4258
      }
4259
   }
4260

4261
   const int nblocks = mir_count_blocks(g->mu);
42,732✔
4262
   for (int i = 0; i < nblocks; i++) {
177,614✔
4263
      mir_block_t b = mir_get_block(g->mu, i);
134,882✔
4264

4265
      const int nops = mir_count_nodes(g->mu, b);
134,882✔
4266
      for (int j = 0; j < nops; j++) {
1,229,641✔
4267
         mir_value_t n = mir_get_node(g->mu, b, j);
1,094,759✔
4268
         const mir_op_t op = mir_get_op(g->mu, n);
1,094,759✔
4269
         if (j == nops - 1 && op == MIR_OP_WAIT) {
1,094,759✔
4270
            mir_block_t target = mir_cast_block(mir_get_arg(g->mu, n, 0));
13,488✔
4271
            if (target.id != 1) {
13,488✔
4272
               // This a kludge: remove it when MIR optimises better
4273
               if (mir_count_nodes(g->mu, target) != 1)
13,188✔
4274
                  g->stateless = false;
5,463✔
4275
               else {
4276
                  mir_value_t n0 = mir_get_node(g->mu, target, 0);
7,725✔
4277
                  if (mir_get_op(g->mu, n0) != MIR_OP_JUMP)
7,725✔
4278
                     g->stateless = false;
155✔
4279
                  else if (mir_cast_block(mir_get_arg(g->mu, n0, 0)).id != 1)
7,570✔
4280
                     g->stateless = false;
241✔
4281
               }
4282
            }
4283
         }
4284
         else if (j == nops - 1 && op == MIR_OP_PCALL)
1,081,271✔
4285
            g->stateless = false;
875✔
4286
         else if (op == MIR_OP_CONTEXT_UPREF) {
1,080,396✔
4287
            const int hops = irgen_get_const(g, n, 0);
8,648✔
4288
            if (hops == 0) {
8,648✔
4289
               g->needs_context = true;
987✔
4290
               g->stateless = false;
987✔
4291
            }
4292
         }
4293
      }
4294
   }
4295
}
42,732✔
4296

4297
static void irgen_instance_entry(jit_irgen_t *g)
9,480✔
4298
{
4299
   const ffi_type_t types[] = { FFI_POINTER, FFI_POINTER };
9,480✔
4300
   g->func->spec = ffi_spec_new(types, ARRAY_LEN(types));
9,480✔
4301

4302
#ifdef DEBUG
4303
   // Instances should only be initialised once
4304
   irgen_label_t *cont = irgen_alloc_label(g);
9,480✔
4305
   jit_value_t priv = macro_getpriv(g, g->func->handle);
9,480✔
4306
   j_cmp(g, JIT_CC_EQ, priv, jit_value_from_int64(0));
9,480✔
4307
   j_jump(g, JIT_CC_T, cont);
9,480✔
4308
   j_trap(g);
9,480✔
4309
   irgen_bind_label(g, cont);
9,480✔
4310
#endif
4311

4312
   irgen_locals(g);
9,480✔
4313

4314
   // Stash context pointer
4315
   jit_value_t context = j_recv(g, 0);
9,480✔
4316
   j_store(g, JIT_SZ_PTR, context, jit_addr_from_value(g->statereg, 0));
9,480✔
4317

4318
   macro_putpriv(g, g->func->handle, g->statereg);
9,480✔
4319
}
9,480✔
4320

4321
static void irgen_process_entry(jit_irgen_t *g)
8,995✔
4322
{
4323
   const ffi_type_t types[] = { FFI_POINTER, FFI_POINTER, FFI_POINTER };
8,995✔
4324
   g->func->spec = ffi_spec_new(types, ARRAY_LEN(types));
8,995✔
4325

4326
   if (!g->stateless)
8,995✔
4327
      irgen_jump_table(g);
3,610✔
4328

4329
   irgen_locals(g);
8,995✔
4330

4331
   if (g->stateless) {
8,995✔
4332
      g->contextarg = j_recv(g, 1);
5,385✔
4333

4334
      jit_value_t state = j_recv(g, 0);
5,385✔
4335
      j_cmp(g, JIT_CC_EQ, state, jit_null_ptr());
5,385✔
4336
      j_jump(g, JIT_CC_F, g->blocks[1]);
5,385✔
4337
   }
4338
   else {
4339
      // Stash context pointer
4340
      jit_value_t context = j_recv(g, 1);
3,610✔
4341
      j_store(g, JIT_SZ_PTR, context, jit_addr_from_value(g->statereg, 0));
3,610✔
4342
   }
4343
}
8,995✔
4344

4345
static void irgen_property_entry(jit_irgen_t *g)
210✔
4346
{
4347
   irgen_params(g, 1);
210✔
4348

4349
   if (g->stateless)
210✔
4350
      irgen_locals(g);
183✔
4351

4352
   jit_value_t state = j_recv(g, 0);
210✔
4353
   j_cmp(g, JIT_CC_EQ, state, jit_null_ptr());
210✔
4354
   j_jump(g, JIT_CC_F, g->blocks[1]);
210✔
4355

4356
   if (g->stateless)
210✔
4357
      g->contextarg = g->params[0];
183✔
4358
   else
4359
      g->statereg = state;
27✔
4360

4361
   if (!g->stateless) {
210✔
4362
      irgen_locals(g);
27✔
4363

4364
      // Stash context pointer
4365
      jit_value_t context = jit_addr_from_value(g->statereg, 0);
27✔
4366
      j_store(g, JIT_SZ_PTR, g->params[0], context);
27✔
4367
   }
4368
}
210✔
4369

4370
static void irgen_function_entry(jit_irgen_t *g)
10,646✔
4371
{
4372
   const bool is_procedure = mir_is_null(mir_get_result(g->mu));
10,646✔
4373
   const int first_param = is_procedure ? 1 : 0;
10,646✔
4374
   irgen_params(g, first_param);
10,646✔
4375

4376
   irgen_locals(g);
10,646✔
4377

4378
   if (g->statereg.kind != JIT_VALUE_INVALID) {
10,646✔
4379
      // Stash context pointer
4380
      j_store(g, JIT_SZ_PTR, g->params[0], jit_addr_from_value(g->statereg, 0));
83✔
4381
   }
4382
}
10,646✔
4383

4384
static void irgen_procedure_entry(jit_irgen_t *g)
246✔
4385
{
4386
   irgen_jump_table(g);
246✔
4387
   irgen_params(g, 1);
246✔
4388
   irgen_locals(g);
246✔
4389

4390
   // Stash context pointer
4391
   j_store(g, JIT_SZ_PTR, g->params[0], jit_addr_from_value(g->statereg, 0));
246✔
4392
}
246✔
4393

4394
static void irgen_thunk_entry(jit_irgen_t *g)
11,286✔
4395
{
4396
   g->contextarg = j_recv(g, 0);
11,286✔
4397
   irgen_locals(g);
11,286✔
4398
}
11,286✔
4399

4400
static void irgen_package_entry(jit_irgen_t *g)
1,619✔
4401
{
4402
   // It's harmless to initialise a package multiple times, just return
4403
   // the existing context pointer
4404
   irgen_label_t *cont = irgen_alloc_label(g);
1,619✔
4405
   jit_value_t priv = macro_getpriv(g, g->func->handle);
1,619✔
4406
   j_cmp(g, JIT_CC_EQ, priv, jit_value_from_int64(0));
1,619✔
4407
   j_jump(g, JIT_CC_T, cont);
1,619✔
4408
   j_send(g, 0, priv);
1,619✔
4409
   j_ret(g);
1,619✔
4410
   irgen_bind_label(g, cont);
1,619✔
4411

4412
   irgen_locals(g);
1,619✔
4413

4414
   // Stash context pointer
4415
   jit_value_t context = j_recv(g, 0);
1,619✔
4416
   j_store(g, JIT_SZ_PTR, context, jit_addr_from_value(g->statereg, 0));
1,619✔
4417

4418
   macro_putpriv(g, g->func->handle, g->statereg);
1,619✔
4419
}
1,619✔
4420

4421
static void irgen_protected_entry(jit_irgen_t *g)
172✔
4422
{
4423
   const ffi_type_t types[] = { FFI_POINTER };
172✔
4424
   g->func->spec = ffi_spec_new(types, ARRAY_LEN(types));
172✔
4425

4426
   irgen_params(g, 1);
172✔
4427
   irgen_locals(g);
172✔
4428

4429
   // Stash context pointer
4430
   jit_value_t context = j_recv(g, 0);
172✔
4431
   j_store(g, JIT_SZ_PTR, context, jit_addr_from_value(g->statereg, 0));
172✔
4432
}
172✔
4433

4434
static void irgen_shape_entry(jit_irgen_t *g)
78✔
4435
{
4436
   // TODO: shouldn't really generate code for this
4437
   irgen_locals(g);
78✔
4438
   j_trap(g);
78✔
4439
}
78✔
4440

4441
void jit_irgen(jit_func_t *f, mir_unit_t *mu)
42,732✔
4442
{
4443
   assert(load_acquire(&f->state) == JIT_FUNC_COMPILING);
42,732✔
4444
   assert(f->irbuf == NULL);
42,732✔
4445

4446
   const bool debug_log = opt_get_int(OPT_JIT_LOG) && f->name != NULL;
42,732✔
4447
   const uint64_t start_ticks = debug_log ? get_timestamp_us() : 0;
42,732✔
4448

4449
   const int num_nodes = mir_count_nodes(mu, MIR_NULL_BLOCK);
42,732✔
4450

4451
   jit_irgen_t *g = xcalloc(sizeof(jit_irgen_t));
42,732✔
4452
   g->func = f;
42,732✔
4453
   g->map  = xmalloc_array(num_nodes, sizeof(jit_value_t));
42,732✔
4454
   g->mu   = mu;
42,732✔
4455

4456
   const int nblocks = mir_count_blocks(g->mu);
42,732✔
4457
   g->blocks = xmalloc_array(nblocks, sizeof(irgen_label_t *));
42,732✔
4458

4459
   for (int i = 0; i < nblocks; i++)
177,614✔
4460
      g->blocks[i] = irgen_alloc_label(g);
134,882✔
4461

4462
   irgen_analyse(g);
42,732✔
4463

4464
   switch (mir_get_kind(g->mu)) {
42,732✔
4465
   case MIR_UNIT_INSTANCE:
9,480✔
4466
      irgen_instance_entry(g);
9,480✔
4467
      break;
9,480✔
4468
   case MIR_UNIT_PROCESS:
8,995✔
4469
      irgen_process_entry(g);
8,995✔
4470
      break;
8,995✔
4471
   case MIR_UNIT_FUNCTION:
10,646✔
4472
      irgen_function_entry(g);
10,646✔
4473
      break;
10,646✔
4474
   case MIR_UNIT_PROCEDURE:
246✔
4475
      irgen_procedure_entry(g);
246✔
4476
      break;
246✔
4477
   case MIR_UNIT_THUNK:
11,286✔
4478
      irgen_thunk_entry(g);
11,286✔
4479
      break;
11,286✔
4480
   case MIR_UNIT_PACKAGE:
1,619✔
4481
      irgen_package_entry(g);
1,619✔
4482
      break;
1,619✔
4483
   case MIR_UNIT_PROTECTED:
172✔
4484
      irgen_protected_entry(g);
172✔
4485
      break;
172✔
4486
   case MIR_UNIT_PROPERTY:
210✔
4487
      irgen_property_entry(g);
210✔
4488
      break;
210✔
4489
   case MIR_UNIT_PLACEHOLDER:
78✔
4490
      irgen_shape_entry(g);
78✔
4491
      break;
78✔
UNCOV
4492
   default:
×
4493
      should_not_reach_here();
4494
   }
4495

4496
   for (int i = 0; i < nblocks; i++)
177,614✔
4497
      irgen_block(g, mir_get_block(mu, i));
134,882✔
4498

4499
   f->nregs   = g->next_reg;
42,732✔
4500
   f->cpoolsz = g->cpoolptr;
42,732✔
4501
   f->object  = mir_get_object(g->mu);
42,732✔
4502

4503
   for (irgen_label_t *it = g->labels, *tmp; it; it = tmp) {
256,116✔
4504
      assert(it->label < g->func->nirs);
213,384✔
4505
      if (it->uses > 0)
213,384✔
4506
         g->func->irbuf[it->label].target = 1;
143,147✔
4507
      tmp = it->next;
213,384✔
4508
      free(it);
213,384✔
4509
   }
4510
   g->labels = NULL;
42,732✔
4511

4512
   if (mir_get_kind(mu) != MIR_UNIT_THUNK) {
42,732✔
4513
      jit_do_mem2reg(f);
31,446✔
4514
      jit_do_lvn(f);
31,446✔
4515
      jit_do_cprop(f);
31,446✔
4516
      jit_do_dce(f);
31,446✔
4517
      jit_delete_nops(f);
31,446✔
4518
      jit_free_cfg(f);
31,446✔
4519
   }
4520

4521
   // Function can be executed immediately after this store
4522
   store_release(&(f->state), JIT_FUNC_READY);
42,732✔
4523

4524
   if (opt_get_verbose(OPT_JIT_VERBOSE, istr(f->name))) {
42,732✔
4525
#ifdef DEBUG
UNCOV
4526
      jit_dump_interleaved(f, mu);
×
4527
#else
4528
      jit_dump(f);
4529
#endif
4530
   }
4531

4532
   if (debug_log) {
42,732✔
4533
      const int ticks = get_timestamp_us() - start_ticks;
×
UNCOV
4534
      diag_t *d = diag_new(DIAG_DEBUG, NULL);
×
UNCOV
4535
      diag_printf(d, "%s: %d instructions", istr(f->name), f->nirs);
×
UNCOV
4536
      if (f->cpoolsz > 0)
×
UNCOV
4537
         diag_printf(d, "; %d cpool bytes", f->cpoolsz);
×
UNCOV
4538
      diag_printf(d, " [%d us]", ticks);
×
UNCOV
4539
      diag_emit(d);
×
4540
   }
4541

4542
   free(g->blocks);
42,732✔
4543
   free(g->map);
42,732✔
4544
   free(g->vars);
42,732✔
4545
   free(g->params);
42,732✔
4546
   free(g);
42,732✔
4547
}
42,732✔
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

© 2025 Coveralls, Inc