1 /*
2 * IR - Lightweight JIT Compilation Framework
3 * (IR saver)
4 * Copyright (C) 2022 Zend by Perforce.
5 * Authors: Dmitry Stogov <dmitry@php.net>
6 */
7
8 #include "ir.h"
9 #include "ir_private.h"
10
ir_print_proto(const ir_ctx * ctx,ir_ref func_proto,FILE * f)11 void ir_print_proto(const ir_ctx *ctx, ir_ref func_proto, FILE *f)
12 {
13 ir_ref j;
14
15 if (func_proto) {
16 const ir_proto_t *proto = (const ir_proto_t *)ir_get_str(ctx, func_proto);
17
18 fprintf(f, "(");
19 if (proto->params_count > 0) {
20 fprintf(f, "%s", ir_type_cname[proto->param_types[0]]);
21 for (j = 1; j < proto->params_count; j++) {
22 fprintf(f, ", %s", ir_type_cname[proto->param_types[j]]);
23 }
24 if (proto->flags & IR_VARARG_FUNC) {
25 fprintf(f, ", ...");
26 }
27 } else if (proto->flags & IR_VARARG_FUNC) {
28 fprintf(f, "...");
29 }
30 fprintf(f, "): %s", ir_type_cname[proto->ret_type]);
31 if (proto->flags & IR_FASTCALL_FUNC) {
32 fprintf(f, " __fastcall");
33 } else if (proto->flags & IR_BUILTIN_FUNC) {
34 fprintf(f, " __builtin");
35 }
36 } else {
37 fprintf(f, "(): int32_t");
38 }
39 }
40
ir_save(const ir_ctx * ctx,FILE * f)41 void ir_save(const ir_ctx *ctx, FILE *f)
42 {
43 ir_ref i, j, n, ref, *p;
44 ir_insn *insn;
45 uint32_t flags;
46 bool first;
47
48 fprintf(f, "{\n");
49 for (i = IR_UNUSED + 1, insn = ctx->ir_base - i; i < ctx->consts_count; i++, insn--) {
50 fprintf(f, "\t%s c_%d = ", ir_type_cname[insn->type], i);
51 if (insn->op == IR_FUNC) {
52 fprintf(f, "func %s", ir_get_str(ctx, insn->val.name));
53 ir_print_proto(ctx, insn->proto, f);
54 } else if (insn->op == IR_SYM) {
55 fprintf(f, "sym(%s)", ir_get_str(ctx, insn->val.name));
56 } else if (insn->op == IR_FUNC_ADDR) {
57 fprintf(f, "func *");
58 ir_print_const(ctx, insn, f, true);
59 ir_print_proto(ctx, insn->proto, f);
60 } else {
61 ir_print_const(ctx, insn, f, true);
62 }
63 fprintf(f, ";\n");
64 }
65
66 for (i = IR_UNUSED + 1, insn = ctx->ir_base + i; i < ctx->insns_count;) {
67 flags = ir_op_flags[insn->op];
68 if (flags & IR_OP_FLAG_CONTROL) {
69 if (!(flags & IR_OP_FLAG_MEM) || insn->type == IR_VOID) {
70 fprintf(f, "\tl_%d = ", i);
71 } else {
72 fprintf(f, "\t%s d_%d, l_%d = ", ir_type_cname[insn->type], i, i);
73 }
74 } else {
75 fprintf(f, "\t");
76 if (flags & IR_OP_FLAG_DATA) {
77 fprintf(f, "%s d_%d = ", ir_type_cname[insn->type], i);
78 }
79 }
80 fprintf(f, "%s", ir_op_name[insn->op]);
81 n = ir_operands_count(ctx, insn);
82 if ((insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) && n != 2) {
83 fprintf(f, "/%d", n);
84 } else if ((insn->op == IR_CALL || insn->op == IR_TAILCALL) && n != 2) {
85 fprintf(f, "/%d", n - 2);
86 } else if (insn->op == IR_PHI && n != 3) {
87 fprintf(f, "/%d", n - 1);
88 } else if (insn->op == IR_SNAPSHOT) {
89 fprintf(f, "/%d", n - 1);
90 }
91 first = 1;
92 for (j = 1, p = insn->ops + 1; j <= n; j++, p++) {
93 uint32_t opnd_kind = IR_OPND_KIND(flags, j);
94
95 ref = *p;
96 if (ref) {
97 switch (opnd_kind) {
98 case IR_OPND_DATA:
99 if (IR_IS_CONST_REF(ref)) {
100 fprintf(f, "%sc_%d", first ? "(" : ", ", -ref);
101 } else {
102 fprintf(f, "%sd_%d", first ? "(" : ", ", ref);
103 }
104 first = 0;
105 break;
106 case IR_OPND_CONTROL:
107 case IR_OPND_CONTROL_DEP:
108 case IR_OPND_CONTROL_REF:
109 fprintf(f, "%sl_%d", first ? "(" : ", ", ref);
110 first = 0;
111 break;
112 case IR_OPND_STR:
113 fprintf(f, "%s\"%s\"", first ? "(" : ", ", ir_get_str(ctx, ref));
114 first = 0;
115 break;
116 case IR_OPND_PROTO:
117 fprintf(f, "%sfunc ", first ? "(" : ", ");
118 ir_print_proto(ctx, ref, f);
119 break;
120 case IR_OPND_PROB:
121 if (ref == 0) {
122 break;
123 }
124 IR_FALLTHROUGH;
125 case IR_OPND_NUM:
126 fprintf(f, "%s%d", first ? "(" : ", ", ref);
127 first = 0;
128 break;
129 }
130 } else if (opnd_kind == IR_OPND_NUM) {
131 fprintf(f, "%s%d", first ? "(" : ", ", ref);
132 first = 0;
133 } else if (j != n &&
134 (IR_IS_REF_OPND_KIND(opnd_kind) || (opnd_kind == IR_OPND_UNUSED && p[n-j]))) {
135 fprintf(f, "%snull", first ? "(" : ", ");
136 first = 0;
137 }
138 }
139 if (first) {
140 fprintf(f, ";");
141 } else {
142 fprintf(f, ");");
143 }
144 if (((flags & IR_OP_FLAG_DATA) || ((flags & IR_OP_FLAG_MEM) && insn->type != IR_VOID)) && ctx->binding) {
145 ir_ref var = ir_binding_find(ctx, i);
146 if (var) {
147 IR_ASSERT(var < 0);
148 fprintf(f, " # BIND(0x%x);", -var);
149 }
150 }
151 fprintf(f, "\n");
152 n = ir_insn_inputs_to_len(n);
153 i += n;
154 insn += n;
155 }
156 fprintf(f, "}\n");
157 }
158