xref: /PHP-8.2/ext/opcache/jit/ir/ir_save.c (revision 215c5cfe)
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