Coverage Report

Created: 2026-10-28 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/opcache/jit/ir/ir_check.c
Line
Count
Source
1
/*
2
 * IR - Lightweight JIT Compilation Framework
3
 * (IR verification)
4
 * This file is part of the IR Project distributed under the MIT-style LICENSE.
5
 * Authors: Dmitry Stogov <dmitry@php.net>
6
 */
7
8
#include "ir.h"
9
#include "ir_private.h"
10
11
void ir_consistency_check(void)
12
0
{
13
0
  IR_ASSERT(IR_UNUSED == 0);
14
0
  IR_ASSERT(IR_NOP == 0);
15
16
0
  IR_ASSERT((int)IR_BOOL   == (int)IR_C_BOOL);
17
0
  IR_ASSERT((int)IR_U8     == (int)IR_C_U8);
18
0
  IR_ASSERT((int)IR_U16    == (int)IR_C_U16);
19
0
  IR_ASSERT((int)IR_U32    == (int)IR_C_U32);
20
0
  IR_ASSERT((int)IR_U64    == (int)IR_C_U64);
21
0
  IR_ASSERT((int)IR_ADDR   == (int)IR_C_ADDR);
22
0
  IR_ASSERT((int)IR_CHAR   == (int)IR_C_CHAR);
23
0
  IR_ASSERT((int)IR_I8     == (int)IR_C_I8);
24
0
  IR_ASSERT((int)IR_I16    == (int)IR_C_I16);
25
0
  IR_ASSERT((int)IR_I32    == (int)IR_C_I32);
26
0
  IR_ASSERT((int)IR_I64    == (int)IR_C_I64);
27
0
  IR_ASSERT((int)IR_DOUBLE == (int)IR_C_DOUBLE);
28
0
  IR_ASSERT((int)IR_FLOAT  == (int)IR_C_FLOAT);
29
30
0
  IR_ASSERT((IR_EQ ^ 1) == IR_NE);
31
0
  IR_ASSERT((IR_LT ^ 3) == IR_GT);
32
0
  IR_ASSERT((IR_GT ^ 3) == IR_LT);
33
0
  IR_ASSERT((IR_LE ^ 3) == IR_GE);
34
0
  IR_ASSERT((IR_GE ^ 3) == IR_LE);
35
0
  IR_ASSERT((IR_ULT ^ 3) == IR_UGT);
36
0
  IR_ASSERT((IR_UGT ^ 3) == IR_ULT);
37
0
  IR_ASSERT((IR_ULE ^ 3) == IR_UGE);
38
0
  IR_ASSERT((IR_UGE ^ 3) == IR_ULE);
39
0
  IR_ASSERT((IR_ORDERED ^ 1) == IR_UNORDERED);
40
41
0
  IR_ASSERT(IR_ADD + 1 == IR_SUB);
42
0
}
43
44
typedef struct {
45
  ir_arena  *arena;
46
  ir_bitset *use_set;
47
  ir_bitset *input_set;
48
} ir_check_ctx;
49
50
static bool ir_check_use_list(ir_check_ctx *check_ctx, const ir_ctx *ctx, ir_ref from, ir_ref to)
51
5.22M
{
52
5.22M
  ir_ref n, *p;
53
5.22M
  ir_use_list *use_list = &ctx->use_lists[from];
54
55
5.22M
  n = use_list->count;
56
5.22M
  if (n > 16) {
57
    /* Avoid quadratic complexity by maintaining a temporary bit-set */
58
612
    ir_bitset set;
59
60
612
    if (!check_ctx->use_set || !(set = check_ctx->use_set[from])) {
61
34
      if (!check_ctx->arena) {
62
32
        check_ctx->arena = ir_arena_create(sizeof(ir_arena) +
63
32
          ctx->insns_count * sizeof(ir_bitset) +
64
32
          ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
65
32
      }
66
34
      if (!check_ctx->use_set) {
67
32
        check_ctx->use_set = ir_arena_alloc(&check_ctx->arena, ctx->insns_count * sizeof(ir_bitset));
68
32
        memset(check_ctx->use_set, 0, ctx->insns_count * sizeof(ir_bitset));
69
32
      }
70
34
      check_ctx->use_set[from] = set = (ir_bitset)ir_arena_alloc(&check_ctx->arena,
71
34
        ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
72
34
      memset(set, 0, ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
73
646
      for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
74
612
        ir_bitset_incl(set, *p);
75
612
      }
76
34
    }
77
612
    return ir_bitset_in(set, to);
78
612
  }
79
7.92M
  for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
80
7.92M
    if (*p == to) {
81
5.21M
      return 1;
82
5.21M
    }
83
7.92M
  }
84
0
  return 0;
85
5.21M
}
86
87
static bool ir_check_input_list(ir_check_ctx *check_ctx, const ir_ctx *ctx, ir_ref from, ir_ref to)
88
5.22M
{
89
5.22M
  ir_insn *insn = &ctx->ir_base[to];
90
5.22M
  ir_ref n, j, *p;
91
92
5.22M
  n = ir_input_edges_count(ctx, insn);
93
5.22M
  if (n > 16) {
94
    /* Avoid quadratic complexity by maintaining a temporary bit-set */
95
0
    ir_bitset set;
96
97
0
    if (!check_ctx->input_set || !(set = check_ctx->input_set[to])) {
98
0
      if (!check_ctx->arena) {
99
0
        check_ctx->arena = ir_arena_create(sizeof(ir_arena) +
100
0
          ctx->insns_count * sizeof(ir_bitset) +
101
0
          ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
102
0
      }
103
0
      if (!check_ctx->input_set) {
104
0
        check_ctx->input_set = ir_arena_alloc(&check_ctx->arena, ctx->insns_count * sizeof(ir_bitset));
105
0
        memset(check_ctx->input_set, 0, ctx->insns_count * sizeof(ir_bitset));
106
0
      }
107
0
      check_ctx->input_set[to] = set = (ir_bitset)ir_arena_alloc(&check_ctx->arena,
108
0
        ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
109
0
      memset(set, 0, ir_bitset_len(ctx->insns_count) * sizeof(ir_bitset_base_t));
110
0
      for (j = 1, p = insn->ops + 1; j <= n; j++, p++) {
111
0
        if (*p > 0) ir_bitset_incl(set, *p);
112
0
      }
113
0
    }
114
0
    return ir_bitset_in(set, from);
115
0
  }
116
7.00M
  for (j = 1, p = insn->ops + 1; j <= n; j++, p++) {
117
7.00M
    if (*p == from) {
118
5.22M
      return 1;
119
5.22M
    }
120
7.00M
  }
121
0
  return 0;
122
5.22M
}
123
124
static bool ir_check_domination(const ir_ctx *ctx, ir_ref def, ir_ref use)
125
1.04M
{
126
1.04M
  uint32_t b1 = ctx->cfg_map[def];
127
1.04M
  uint32_t b2 = ctx->cfg_map[use];
128
1.04M
  ir_block *blocks = ctx->cfg_blocks;
129
1.04M
  uint32_t b1_depth = blocks[b1].dom_depth;
130
1.04M
  const ir_block *bb2 = &blocks[b2];
131
132
1.04M
  if (b1 == b2) {
133
882k
    return def < use;
134
882k
  }
135
456k
  while (bb2->dom_depth > b1_depth) {
136
294k
    b2 = bb2->dom_parent;
137
294k
    bb2 = &blocks[b2];
138
294k
  }
139
161k
  return b1 == b2;
140
1.04M
}
141
142
bool ir_check(const ir_ctx *ctx)
143
29.8k
{
144
29.8k
  ir_ref i, j, n, *p, use;
145
29.8k
  ir_insn *insn, *use_insn;
146
29.8k
  ir_type type;
147
29.8k
  uint32_t flags;
148
29.8k
  bool ok = 1;
149
29.8k
  ir_check_ctx check_ctx;
150
151
29.8k
  if (ctx->insns_count < 1 || ctx->ir_base[1].op != IR_START) {
152
0
    fprintf(stderr, "ir_base[1].op invalid opcode (%d)\n",
153
0
      (ctx->insns_count < 1) ? IR_NOP : ctx->ir_base[0].op);
154
0
    ok = 0;
155
0
  }
156
157
29.8k
  check_ctx.arena = NULL;
158
29.8k
  check_ctx.use_set = NULL;
159
29.8k
  check_ctx.input_set = NULL;
160
161
5.29M
  for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) {
162
5.26M
    if (insn->op >= IR_LAST_OP) {
163
0
      fprintf(stderr, "ir_base[%d].op invalid opcode (%d)\n", i, insn->op);
164
0
      ok = 0;
165
0
      break;
166
0
    }
167
5.26M
    flags = ir_op_flags[insn->op];
168
5.26M
    n = ir_input_edges_count(ctx, insn);
169
14.9M
    for (j = 1, p = insn->ops + 1; j <= n; j++, p++) {
170
9.65M
      use = *p;
171
9.65M
      if (use != IR_UNUSED) {
172
9.64M
        if (IR_IS_CONST_REF(use)) {
173
1.81M
          if (IR_OPND_KIND(flags, j) != IR_OPND_DATA) {
174
0
            fprintf(stderr, "ir_base[%d].ops[%d] reference (%d) must not be constant\n", i, j, use);
175
0
            ok = 0;
176
1.81M
          } else if (-use >= ctx->consts_count) {
177
0
            fprintf(stderr, "ir_base[%d].ops[%d] constant reference (%d) is out of range\n", i, j, use);
178
0
            ok = 0;
179
0
          }
180
7.83M
        } else {
181
7.83M
          if (use >= ctx->insns_count) {
182
0
            fprintf(stderr, "ir_base[%d].ops[%d] insn reference (%d) is out of range\n", i, j, use);
183
0
            ok = 0;
184
0
            continue;
185
0
          }
186
7.83M
          use_insn = &ctx->ir_base[use];
187
7.83M
          switch (IR_OPND_KIND(flags, j)) {
188
3.28M
            case IR_OPND_DATA:
189
3.28M
              if (!(ir_op_flags[use_insn->op] & IR_OP_FLAG_DATA)) {
190
2.01M
                if (!(ir_op_flags[use_insn->op] & IR_OP_FLAG_MEM)
191
2.01M
                 || use_insn->type == IR_VOID) {
192
0
                  fprintf(stderr, "ir_base[%d].ops[%d] reference (%d) must be DATA\n", i, j, use);
193
0
                  ok = 0;
194
0
                }
195
2.01M
              }
196
3.28M
              if ((ctx->flags2 & IR_LINEAR)
197
1.09M
               && use >= i
198
6.04k
               && !(insn->op == IR_PHI && ctx->ir_base[insn->op1].op == IR_LOOP_BEGIN)) {
199
0
                fprintf(stderr, "ir_base[%d].ops[%d] invalid forward reference (%d)\n", i, j, use);
200
0
                ok = 0;
201
0
              }
202
3.28M
              if (flags & IR_OP_FLAG_DATA) {
203
1.22M
                switch (insn->op) {
204
0
                  case IR_COND:
205
0
                    if (j == 1) {
206
0
                      break;
207
0
                    }
208
0
                    IR_FALLTHROUGH;
209
684k
                  case IR_ADD:
210
778k
                  case IR_SUB:
211
798k
                  case IR_MUL:
212
798k
                  case IR_DIV:
213
803k
                  case IR_MOD:
214
803k
                  case IR_NEG:
215
803k
                  case IR_ABS:
216
803k
                  case IR_ADD_OV:
217
803k
                  case IR_SUB_OV:
218
804k
                  case IR_MUL_OV:
219
804k
                  case IR_NOT:
220
805k
                  case IR_OR:
221
925k
                  case IR_AND:
222
925k
                  case IR_XOR:
223
925k
                  case IR_SHL:
224
926k
                  case IR_SHR:
225
926k
                  case IR_SAR:
226
926k
                  case IR_ROL:
227
926k
                  case IR_ROR:
228
926k
                  case IR_BSWAP:
229
927k
                  case IR_MIN:
230
927k
                  case IR_MAX:
231
1.06M
                  case IR_PHI:
232
1.07M
                  case IR_COPY:
233
1.07M
                  case IR_PI:
234
1.07M
                    if (insn->type != use_insn->type) {
235
36
                      if (j == 2
236
6
                       && (insn->op == IR_SHL
237
0
                        || insn->op == IR_SHR
238
0
                        || insn->op == IR_SAR
239
0
                        || insn->op == IR_ROL
240
0
                        || insn->op == IR_ROR)
241
6
                       && IR_IS_TYPE_INT(use_insn->type)
242
6
                       && (IR_IS_TYPE_INT(insn->type) || IR_IS_TYPE_VECTOR(insn->type))) {
243
                        /* second argument of SHIFT may be incompatible with result */
244
6
                        break;
245
6
                      }
246
30
                      if (insn->op == IR_NOT && insn->type == IR_BOOL) {
247
                        /* boolean not */
248
0
                        break;
249
0
                      }
250
30
                      if (insn->type == IR_ADDR && (use_insn->type == IR_UINTPTR_T || use_insn->type == IR_INTPTR_T)) {
251
30
                        break;
252
30
                      } else if (use_insn->type == IR_ADDR && (insn->type == IR_UINTPTR_T || insn->type == IR_INTPTR_T)) {
253
0
                        break;
254
0
                      }
255
0
                      fprintf(stderr, "ir_base[%d].ops[%d] (%d) type is incompatible with result type (%d != %d)\n",
256
0
                        i, j, use, use_insn->type, insn->type);
257
0
                      ok = 0;
258
0
                    }
259
1.07M
                    break;
260
1.22M
                }
261
1.22M
              }
262
3.28M
              if ((ctx->flags2 & IR_LINEAR)
263
1.09M
               && ctx->cfg_map
264
1.09M
               && insn->op != IR_PHI
265
1.04M
               && !ir_check_domination(ctx, use, i)) {
266
0
                fprintf(stderr, "ir_base[%d].ops[%d] -> %d, %d doesn't dominate %d\n", i, j, use, use, i);
267
0
                ok = 0;
268
0
              }
269
3.28M
              break;
270
4.47M
            case IR_OPND_CONTROL:
271
4.47M
              if (flags & IR_OP_FLAG_BB_START) {
272
1.25M
                if (!(ir_op_flags[use_insn->op] & IR_OP_FLAG_BB_END)) {
273
0
                  fprintf(stderr, "ir_base[%d].ops[%d] reference (%d) must be BB_END\n", i, j, use);
274
0
                  ok = 0;
275
0
                }
276
3.22M
              } else {
277
3.22M
                if (ir_op_flags[use_insn->op] & IR_OP_FLAG_BB_END) {
278
0
                  fprintf(stderr, "ir_base[%d].ops[%d] reference (%d) must not be BB_END\n", i, j, use);
279
0
                  ok = 0;
280
0
                }
281
3.22M
              }
282
4.47M
              if ((ctx->flags2 & IR_LINEAR)
283
1.48M
               && use >= i
284
3.21k
               && !(insn->op == IR_LOOP_BEGIN)) {
285
0
                fprintf(stderr, "ir_base[%d].ops[%d] invalid forward reference (%d)\n", i, j, use);
286
0
                ok = 0;
287
0
              }
288
4.47M
              break;
289
74.1k
            case IR_OPND_CONTROL_DEP:
290
74.1k
              if ((ctx->flags2 & IR_LINEAR)
291
24.6k
               && use >= i) {
292
0
                fprintf(stderr, "ir_base[%d].ops[%d] invalid forward reference (%d)\n", i, j, use);
293
0
                ok = 0;
294
74.1k
              } else if (insn->op == IR_PHI) {
295
73.9k
                ir_insn *merge_insn = &ctx->ir_base[insn->op1];
296
73.9k
                if (merge_insn->op != IR_MERGE && merge_insn->op != IR_LOOP_BEGIN) {
297
0
                  fprintf(stderr, "ir_base[%d].ops[%d] reference (%d) must be MERGE or LOOP_BEGIN\n", i, j, use);
298
0
                  ok = 0;
299
0
                }
300
73.9k
              }
301
74.1k
              break;
302
0
            case IR_OPND_CONTROL_REF:
303
0
              if (!(ir_op_flags[use_insn->op] & IR_OP_FLAG_CONTROL)) {
304
0
                fprintf(stderr, "ir_base[%d].ops[%d] reference (%d) must be CONTROL\n", i, j, use);
305
0
                ok = 0;
306
0
              }
307
0
              break;
308
1.10k
            case IR_OPND_CONTROL_GUARD:
309
1.10k
              if (!(ir_op_flags[use_insn->op] & IR_OP_FLAG_BB_START)
310
0
               && use_insn->op != IR_GUARD
311
0
               && use_insn->op != IR_GUARD_NOT) {
312
0
                fprintf(stderr, "ir_base[%d].ops[%d] reference (%d) must be BB_START or GUARD\n", i, j, use);
313
0
                ok = 0;
314
0
              }
315
1.10k
              break;
316
0
            default:
317
0
              fprintf(stderr, "ir_base[%d].ops[%d] reference (%d) of unsupported kind\n", i, j, use);
318
0
              ok = 0;
319
7.83M
          }
320
7.83M
        }
321
9.64M
      } else if ((insn->op == IR_RETURN || insn->op == IR_UNREACHABLE) && j == 2) {
322
        /* pass (function returns void) */
323
3.62k
      } else if (insn->op == IR_BEGIN && j == 1) {
324
        /* pass (start of unreachable basic block) */
325
3.60k
      } else if (IR_OPND_KIND(flags, j) == IR_OPND_CONTROL_GUARD) {
326
        /* reference to control guard is optional */
327
2.45k
      } else if (IR_OPND_KIND(flags, j) != IR_OPND_CONTROL_REF
328
1.14k
          && (insn->op != IR_SNAPSHOT || j == 1)) {
329
0
        fprintf(stderr, "ir_base[%d].ops[%d] missing reference (%d)\n", i, j, use);
330
0
        ok = 0;
331
0
      }
332
9.65M
      if (ctx->use_lists
333
6.43M
       && use > 0
334
5.22M
       && !ir_check_use_list(&check_ctx, ctx, use, i)) {
335
0
        fprintf(stderr, "ir_base[%d].ops[%d] is not in use list (%d)\n", i, j, use);
336
0
        ok = 0;
337
0
      }
338
9.65M
    }
339
340
5.26M
    switch (insn->op) {
341
73.9k
      case IR_PHI:
342
73.9k
        if (insn->inputs_count != ctx->ir_base[insn->op1].inputs_count + 1) {
343
0
          fprintf(stderr, "ir_base[%d] inconsistent PHI inputs_count (%d != %d)\n",
344
0
            i, insn->inputs_count, ctx->ir_base[insn->op1].inputs_count + 1);
345
0
          ok = 0;
346
0
        }
347
73.9k
        break;
348
640k
      case IR_LOAD:
349
640k
      case IR_LOAD_v:
350
1.07M
      case IR_STORE:
351
1.07M
      case IR_STORE_v:
352
1.07M
        type = ctx->ir_base[insn->op2].type;
353
1.07M
        if (type != IR_ADDR
354
0
         && (!IR_IS_TYPE_INT(type) || ir_type_size[type] != ir_type_size[IR_ADDR])) {
355
0
          fprintf(stderr, "ir_base[%d].op2 must have ADDR type (%s)\n",
356
0
            i, IR_IS_TYPE_VECTOR(type) ? "VECTOR" : ir_type_name[type]);
357
0
          ok = 0;
358
0
        }
359
1.07M
        break;
360
0
      case IR_VLOAD:
361
0
      case IR_VLOAD_v:
362
0
      case IR_VSTORE:
363
0
      case IR_VSTORE_v:
364
0
        if (ctx->ir_base[insn->op2].op != IR_VAR) {
365
0
          fprintf(stderr, "ir_base[%d].op2 must be 'VAR' (%s)\n",
366
0
            i, ir_op_name[ctx->ir_base[insn->op2].op]);
367
0
          ok = 0;
368
0
        }
369
0
        break;
370
180
      case IR_RETURN:
371
180
        if (ctx->ret_type != (insn->op2 ? ctx->ir_base[insn->op2].type : IR_VOID)) {
372
0
          fprintf(stderr, "ir_base[%d].type incompatible return type\n", i);
373
0
          ok = 0;
374
0
        }
375
180
        break;
376
38.8k
      case IR_TAILCALL:
377
38.8k
        if (ctx->ret_type != insn->type) {
378
0
          fprintf(stderr, "ir_base[%d].type incompatible return type\n", i);
379
0
          ok = 0;
380
0
        }
381
38.8k
        break;
382
132
      case IR_PARAM:
383
132
        if (i > 2 && ctx->ir_base[i - 1].op != IR_PARAM) {
384
0
          fprintf(stderr, "ir_base[%d].op PARAMs must be used only right after START\n", i);
385
0
          ok = 0;
386
0
        }
387
132
        break;
388
5.26M
    }
389
390
5.26M
    if (ctx->use_lists) {
391
3.50M
      ir_use_list *use_list = &ctx->use_lists[i];
392
3.50M
      ir_ref count, n = use_list->count;
393
394
8.72M
      for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
395
5.22M
        use = *p;
396
5.22M
        if (!ir_check_input_list(&check_ctx, ctx, i, use)) {
397
0
          fprintf(stderr, "ir_base[%d] is in use list of ir_base[%d]\n", use, i);
398
0
          ok = 0;
399
0
        }
400
5.22M
      }
401
402
3.50M
      if ((flags & IR_OP_FLAG_CONTROL) && !(flags & IR_OP_FLAG_MEM)) {
403
1.36M
        switch (insn->op) {
404
12
          case IR_SWITCH:
405
            /* may have many successors */
406
12
            if (use_list->count < 1) {
407
0
              fprintf(stderr, "ir_base[%d].op (SWITCH) must have at least 1 successor (%d)\n", i, use_list->count);
408
0
              ok = 0;
409
0
            }
410
12
            break;
411
228k
          case IR_IF:
412
228k
            if (use_list->count != 2) {
413
0
              fprintf(stderr, "ir_base[%d].op (IF) must have 2 successors (%d)\n", i, use_list->count);
414
0
              ok = 0;
415
0
            }
416
228k
            break;
417
25.8k
          case IR_UNREACHABLE:
418
25.9k
          case IR_RETURN:
419
25.9k
            if (use_list->count == 1) {
420
              /* UNREACHABLE and RETURN may be linked with the following ENTRY by a fake edge */
421
6.25k
              if (ctx->ir_base[ctx->use_edges[use_list->refs]].op == IR_ENTRY) {
422
6.25k
                break;
423
6.25k
              }
424
6.25k
            }
425
19.7k
            IR_FALLTHROUGH;
426
28.7k
          case IR_IJMP:
427
28.7k
            if (use_list->count != 0) {
428
0
              fprintf(stderr, "ir_base[%d].op (%s) must not have successors (%d)\n",
429
0
                i, ir_op_name[insn->op], use_list->count);
430
0
              ok = 0;
431
0
            }
432
28.7k
            break;
433
0
          case IR_IGOTO:
434
0
          case IR_ASM_GOTO:
435
0
            break;
436
1.09M
          default:
437
            /* skip data references */
438
1.09M
            count = n = use_list->count;
439
2.24M
            for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) {
440
1.14M
              use = *p;
441
1.14M
              if (!(ir_op_flags[ctx->ir_base[use].op] & IR_OP_FLAG_CONTROL)) {
442
50.1k
                count--;
443
50.1k
              }
444
1.14M
            }
445
1.09M
            if (count != 1) {
446
66
              if (insn->op == IR_CALL && count == 2) {
447
                /* result of CALL may be used as data in control instruction */
448
0
                break;
449
0
              }
450
66
              if ((insn->op == IR_LOOP_END || insn->op == IR_END) && count == 2) {
451
                /* LOOP_END/END may be linked with the following ENTRY by a fake edge */
452
66
                if (ctx->ir_base[ctx->use_edges[use_list->refs]].op == IR_ENTRY) {
453
66
                  count--;
454
66
                }
455
66
                if (ctx->ir_base[ctx->use_edges[use_list->refs + 1]].op == IR_ENTRY) {
456
0
                  count--;
457
0
                }
458
66
                if (count == 1) {
459
66
                  break;
460
66
                }
461
66
              }
462
0
              if (count == 0 && (insn->op == IR_END || insn->op == IR_LOOP_END)) {
463
                /* Dead block */
464
0
                break;
465
0
              }
466
0
              fprintf(stderr, "ir_base[%d].op (%s) must have 1 successor (%d)\n",
467
0
                i, ir_op_name[insn->op], count);
468
0
              ok = 0;
469
0
            }
470
1.09M
            break;
471
1.36M
        }
472
1.36M
      }
473
3.50M
    }
474
5.26M
    n = ir_insn_inputs_to_len(n);
475
5.26M
    i += n;
476
5.26M
    insn += n;
477
5.26M
  }
478
479
29.8k
  if (check_ctx.arena) {
480
32
    ir_arena_free(check_ctx.arena);
481
32
  }
482
483
//  if (!ok) {
484
//    ir_dump_codegen(ctx, stderr);
485
//  }
486
487
29.8k
#ifndef IR_CHECK_NO_ABORT
488
29.8k
  IR_ASSERT(ok);
489
29.8k
#endif
490
491
29.8k
  return ok;
492
29.8k
}
493
494
bool ir_check_prototype(const ir_ctx *ctx, uint32_t flags, uint8_t ret_type, uint32_t params_count, uint8_t *param_types)
495
0
{
496
0
  bool ok = 1;
497
0
  ir_ref ref = 2;
498
0
  uint32_t n = 0;
499
500
0
  while (ref < ctx->insns_count && ctx->ir_base[ref].op == IR_PARAM) {
501
0
    if (n >= params_count) {
502
0
      fprintf(stderr, "parameter count doesn't match function signature\n");
503
0
      ok = 0;
504
0
      break;
505
0
    } else if (ctx->ir_base[ref].type != param_types[n]) {
506
0
      fprintf(stderr, "parameter %d type doesn't match function signature\n", n);
507
0
      ok = 0;
508
0
    }
509
0
    ref++;
510
0
    n++;
511
0
  }
512
513
0
  if (n < params_count) {
514
0
    fprintf(stderr, "parameter count doesn't match function signature\n");
515
0
    ok = 0;
516
0
  }
517
0
  if ((flags & IR_VARARG_FUNC) != (ctx->flags & IR_VARARG_FUNC)) {
518
0
    fprintf(stderr, "IR_VARARG_FUNC flag doesn't match function signature\n");
519
0
    ok = 0;
520
0
  }
521
0
  if (ret_type != ctx->ret_type) {
522
0
    fprintf(stderr, "return type doesn't match function signature\n");
523
0
    ok = 0;
524
0
  }
525
0
  if ((flags & IR_CALL_CONV_MASK) != (ctx->flags & IR_CALL_CONV_MASK)) {
526
0
    fprintf(stderr, "calling convention doesn't match function signature\n");
527
0
    ok = 0;
528
0
  }
529
530
0
  return ok;
531
0
}