23# if defined(__linux__) || defined(__sun)
26# if defined(__APPLE__) && defined(__aarch64__)
27# include <libkern/OSCacheControl.h>
30# define WIN32_LEAN_AND_MEAN
42# include <valgrind/valgrind.h>
45#define IR_TYPE_FLAGS(name, type, field, flags) ((flags)|sizeof(type)),
46#define IR_TYPE_NAME(name, type, field, flags) #name,
47#define IR_TYPE_CNAME(name, type, field, flags) #type,
48#define IR_TYPE_SIZE(name, type, field, flags) sizeof(type),
49#define IR_OP_NAME(name, flags, op1, op2, op3) #name,
85 case '\\':
fputs(
"\\\\", f);
break;
86 case '\'':
fputs(
"'", f);
break;
87 case '\"':
fputs(
"\\\"", f);
break;
88 case '\a':
fputs(
"\\a", f);
break;
89 case '\b':
fputs(
"\\b", f);
break;
90 case '\033':
fputs(
"\\e", f);
break;
91 case '\f':
fputs(
"\\f", f);
break;
92 case '\n':
fputs(
"\\n", f);
break;
93 case '\r':
fputs(
"\\r", f);
break;
94 case '\t':
fputs(
"\\t", f);
break;
95 case '\v':
fputs(
"\\v", f);
break;
96 case '\?':
fputs(
"\\?", f);
break;
101 if (
ch >= 0 &&
ch < 32) {
104 '0' + ((
ch >> 6) % 8),
105 '0' + ((
ch >> 3) % 8),
121 if (insn->op == IR_FUNC || insn->op == IR_SYM) {
124 }
else if (insn->op == IR_STR) {
138 switch (insn->type) {
155 if (insn->
val.addr) {
162 if (insn->
val.c ==
'\\') {
164 }
else if (insn->
val.c >=
' ') {
166 }
else if (insn->
val.c ==
'\t') {
168 }
else if (insn->
val.c ==
'\r') {
170 }
else if (insn->
val.c ==
'\n') {
172 }
else if (insn->
val.c ==
'\0') {
191 if (isnan(insn->
val.
d)) {
205 if (isnan(insn->
val.f)) {
224#define ir_op_flag_v 0
225#define ir_op_flag_v0X3 (0 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
226#define ir_op_flag_d IR_OP_FLAG_DATA
227#define ir_op_flag_d0 ir_op_flag_d
228#define ir_op_flag_d1 (ir_op_flag_d | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
229#define ir_op_flag_d1X1 (ir_op_flag_d | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
230#define ir_op_flag_d2 (ir_op_flag_d | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
231#define ir_op_flag_d2C (ir_op_flag_d | IR_OP_FLAG_COMMUTATIVE | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
232#define ir_op_flag_d3 (ir_op_flag_d | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
233#define ir_op_flag_r IR_OP_FLAG_DATA
234#define ir_op_flag_r0 ir_op_flag_r
235#define ir_op_flag_p (IR_OP_FLAG_DATA | IR_OP_FLAG_PINNED)
236#define ir_op_flag_p1 (ir_op_flag_p | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
237#define ir_op_flag_p1X1 (ir_op_flag_p | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
238#define ir_op_flag_p1X2 (ir_op_flag_p | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
239#define ir_op_flag_p2 (ir_op_flag_p | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
240#define ir_op_flag_pN (ir_op_flag_p | IR_OP_FLAG_VAR_INPUTS)
241#define ir_op_flag_c IR_OP_FLAG_CONTROL
242#define ir_op_flag_c1X2 (ir_op_flag_c | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
243#define ir_op_flag_c3 (ir_op_flag_c | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
244#define ir_op_flag_S (IR_OP_FLAG_CONTROL|IR_OP_FLAG_BB_START)
245#define ir_op_flag_S0X1 (ir_op_flag_S | 0 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
246#define ir_op_flag_S1 (ir_op_flag_S | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
247#define ir_op_flag_S1X1 (ir_op_flag_S | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
248#define ir_op_flag_S2 (ir_op_flag_S | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
249#define ir_op_flag_S2X1 (ir_op_flag_S | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
250#define ir_op_flag_SN (ir_op_flag_S | IR_OP_FLAG_VAR_INPUTS)
251#define ir_op_flag_E (IR_OP_FLAG_CONTROL|IR_OP_FLAG_BB_END)
252#define ir_op_flag_E1 (ir_op_flag_E | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
253#define ir_op_flag_E2 (ir_op_flag_E | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
254#define ir_op_flag_T (IR_OP_FLAG_CONTROL|IR_OP_FLAG_BB_END|IR_OP_FLAG_TERMINATOR)
255#define ir_op_flag_T2X1 (ir_op_flag_T | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
256#define ir_op_flag_T1X2 (ir_op_flag_T | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
257#define ir_op_flag_l (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_LOAD)
258#define ir_op_flag_l0 ir_op_flag_l
259#define ir_op_flag_l1 (ir_op_flag_l | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
260#define ir_op_flag_l1X1 (ir_op_flag_l | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
261#define ir_op_flag_l1X2 (ir_op_flag_l | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
262#define ir_op_flag_l2 (ir_op_flag_l | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
263#define ir_op_flag_l3 (ir_op_flag_l | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
264#define ir_op_flag_s (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_STORE)
265#define ir_op_flag_s0 ir_op_flag_s
266#define ir_op_flag_s1 (ir_op_flag_s | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
267#define ir_op_flag_s2 (ir_op_flag_s | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
268#define ir_op_flag_s2X1 (ir_op_flag_s | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
269#define ir_op_flag_s3 (ir_op_flag_s | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
270#define ir_op_flag_x1 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
271#define ir_op_flag_x2 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
272#define ir_op_flag_x3 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
273#define ir_op_flag_xN (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_CALL | IR_OP_FLAG_VAR_INPUTS)
274#define ir_op_flag_a1 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_ALLOC | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
275#define ir_op_flag_a2 (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_ALLOC | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
277#define ir_op_kind____ IR_OPND_UNUSED
278#define ir_op_kind_def IR_OPND_DATA
279#define ir_op_kind_ref IR_OPND_DATA
280#define ir_op_kind_src IR_OPND_CONTROL
281#define ir_op_kind_reg IR_OPND_CONTROL_DEP
282#define ir_op_kind_ret IR_OPND_CONTROL_REF
283#define ir_op_kind_str IR_OPND_STR
284#define ir_op_kind_num IR_OPND_NUM
285#define ir_op_kind_fld IR_OPND_STR
286#define ir_op_kind_var IR_OPND_DATA
287#define ir_op_kind_prb IR_OPND_PROB
288#define ir_op_kind_opt IR_OPND_PROB
289#define ir_op_kind_pro IR_OPND_PROTO
291#define _IR_OP_FLAGS(name, flags, op1, op2, op3) \
292 IR_OP_FLAGS(ir_op_flag_ ## flags, ir_op_kind_ ## op1, ir_op_kind_ ## op2, ir_op_kind_ ## op3),
301static void ir_grow_bottom(
ir_ctx *ctx)
331static void ir_grow_top(
ir_ctx *ctx)
355 (ctx->
insns_limit - old_insns_limit) *
sizeof(uint32_t));
474 ir_ref ref = ir_next_const(ctx);
477 insn->optx =
IR_OPT(IR_ADDR, IR_ADDR);
486 ir_insn *prev_insn, *next_insn;
496 prev_insn = next_insn;
497 next = next_insn->prev_const;
501 insn->prev_const = prev_insn->prev_const;
502 prev_insn->prev_const = ref;
517 if (
type == IR_BOOL) {
519 }
else if (
type == IR_ADDR &&
val.u64 == 0) {
528 if (insn->optx == optx) {
536 ref = insn->prev_const;
540 prev = prev_insn->prev_const;
547 ref = ir_next_const(ctx);
549 insn->prev_const =
prev;
813 ir_ref ref = ir_next_insn(ctx);
861 while (ref >= limit) {
863 if (insn->opt == opt && insn->op1 ==
op1 && insn->op2 ==
op2 && insn->op3 == op3) {
866 if (!insn->prev_insn_offset) {
869 ref = ref - (
ir_ref)(uint32_t)insn->prev_insn_offset;
876#define IR_FOLD(X) IR_FOLD1(X, __LINE__)
877#define IR_FOLD1(X, Y) IR_FOLD2(X, Y)
878#define IR_FOLD2(X, Y) case IR_RULE_ ## Y:
880#define IR_FOLD_ERROR(msg) do { \
881 IR_ASSERT(0 && (msg)); \
885#define IR_FOLD_CONST_U(_val) do { \
887 goto ir_fold_const; \
890#define IR_FOLD_CONST_I(_val) do { \
892 goto ir_fold_const; \
895#define IR_FOLD_CONST_D(_val) do { \
897 goto ir_fold_const; \
900#define IR_FOLD_CONST_F(_val) do { \
903 goto ir_fold_const; \
906#define IR_FOLD_COPY(op) do { \
911#define IR_FOLD_BOOL(cond) \
912 IR_FOLD_COPY((cond) ? IR_TRUE : IR_FALSE)
914#define IR_FOLD_NAMED(name) ir_fold_ ## name:
915#define IR_FOLD_DO_NAMED(name) goto ir_fold_ ## name
916#define IR_FOLD_RESTART goto ir_fold_restart
917#define IR_FOLD_CSE goto ir_fold_cse
918#define IR_FOLD_EMIT goto ir_fold_emit
919#define IR_FOLD_NEXT break
921#include "ir_fold_hash.h"
923#define IR_FOLD_RULE(x) ((x) >> 21)
924#define IR_FOLD_KEY(x) ((x) & 0x1fffff)
941 key = (opt &
IR_OPT_OP_MASK) + ((uint32_t)op1_insn->op << 7) + ((uint32_t)op2_insn->op << 14);
944 uint32_t k =
key & any;
945 uint32_t h = _ir_fold_hashkey(k);
946 uint32_t fh = _ir_fold_hash[h];
948#ifdef IR_FOLD_SEMI_PERFECT_HASH
949 || (fh = _ir_fold_hash[h+1], (fh & 0x1fffff) == k)
973 any = ((any & (any << 7)) & 0x1fc000) | (~any & 0x3f80) | 0x7f;
992 ref = _ir_fold_cse(ctx, opt,
op1,
op2, op3);
1003 if (!
prev || ref -
prev > 0xffff) {
1005 insn->prev_insn_offset = 0;
1007 insn->prev_insn_offset = ref -
prev;
1091 for (i = 1,
p = insn->ops + i; i <= (
count|3); i++,
p++) {
1107 count = insn->inputs_count;
1123 count = insn->inputs_count;
1173 uint32_t edges_count;
1182 n = insn->inputs_count;
1186 for (
j =
n,
p = insn->ops + 1;
j > 0;
j--,
p++) {
1199 use_list->
refs = edges_count;
1200 edges_count += use_list->
count;
1201 use_list->
count = 0;
1206 n = insn->inputs_count;
1207 for (
j =
n,
p = insn->ops + 1;
j > 0;
j--,
p++) {
1210 use_list = &lists[def];
1211 edges[use_list->
refs + use_list->
count++] = i;
1228 size_t linked_lists_size, linked_lists_top = 0, edges_count = 0;
1240 n = insn->inputs_count;
1244 for (
j =
n,
p = insn->ops + 1;
j > 0;
j--,
p++) {
1247 use_list = &lists[def];
1249 if (!use_list->
refs) {
1252 use_list->
count = 1;
1254 if (
UNEXPECTED(linked_lists_top >= linked_lists_size)) {
1255 linked_lists_size += 1024;
1259 linked_lists[linked_lists_top] = i;
1260 linked_lists[linked_lists_top + 1] = use_list->
refs;
1261 use_list->
refs = -(linked_lists_top + 1);
1262 linked_lists_top += 2;
1274 for (use_list = lists + ctx->
insns_count - 1; use_list != lists; use_list--) {
1280 edges[--edges_count] = linked_lists[
n - 1];
1281 n = linked_lists[
n];
1284 edges[--edges_count] =
n;
1285 use_list->
refs = edges_count;
1313 use_list->
count -= (
p - q);
1394 if (old_size < new_size) {
1412static int ir_ref_cmp(
const void *p1,
const void *p2)
1432 int i,
j,
n, *
p, use;
1443 for (;
n;
p++,
n--) {
1452 for (i = 0; i <
n;
p++, i++) {
1495 if (
a->refs[
a->size - 1]) {
1531 for (i = 0; i < l->
len; i++) {
1536 return (uint32_t)-1;
1539static uint32_t ir_hashtab_hash_size(uint32_t
size)
1550static void ir_hashtab_resize(
ir_hashtab *tab)
1552 uint32_t old_hash_size = (uint32_t)(-(int32_t)tab->
mask);
1553 char *old_data = tab->
data;
1555 uint32_t hash_size = ir_hashtab_hash_size(
size);
1560 memset(
data, -1, hash_size *
sizeof(uint32_t));
1561 tab->
data =
data + (hash_size *
sizeof(uint32_t));
1562 tab->
mask = (uint32_t)(-(int32_t)hash_size);
1566 ir_mem_free(old_data - (old_hash_size *
sizeof(uint32_t)));
1573 p->next = ((uint32_t*)tab->
data)[(int32_t)
key];
1583 uint32_t hash_size = ir_hashtab_hash_size(
size);
1585 memset(
data, -1, hash_size *
sizeof(uint32_t));
1586 tab->
data = (
data + (hash_size *
sizeof(uint32_t)));
1587 tab->
mask = (uint32_t)(-(int32_t)hash_size);
1595 uint32_t hash_size = (uint32_t)(-(int32_t)tab->
mask);
1596 char *
data = (
char*)tab->
data - (hash_size *
sizeof(uint32_t));
1603 const char *
data = (
const char*)tab->
data;
1609 if (
p->key ==
key) {
1625 if (
p->key ==
key) {
1626 return p->val ==
val;
1632 ir_hashtab_resize(tab);
1643 p->next = ((uint32_t*)
data)[(int32_t)
key];
1648static int ir_hashtab_key_cmp(
const void *b1,
const void *b2)
1656 uint32_t hash_size,
pos, i;
1664 hash_size = ir_hashtab_hash_size(tab->
size);
1665 memset((
char*)tab->
data - (hash_size *
sizeof(uint32_t)), -1, hash_size *
sizeof(uint32_t));
1672 p->next = ((uint32_t*)tab->
data)[(int32_t)
key];
1679static void ir_addrtab_resize(
ir_hashtab *tab)
1681 uint32_t old_hash_size = (uint32_t)(-(int32_t)tab->
mask);
1682 char *old_data = tab->
data;
1684 uint32_t hash_size = ir_hashtab_hash_size(
size);
1689 memset(
data, -1, hash_size *
sizeof(uint32_t));
1690 tab->
data =
data + (hash_size *
sizeof(uint32_t));
1691 tab->
mask = (uint32_t)(-(int32_t)hash_size);
1695 ir_mem_free(old_data - (old_hash_size *
sizeof(uint32_t)));
1701 uint32_t
key = (uint32_t)
p->key | tab->
mask;
1702 p->next = ((uint32_t*)tab->
data)[(int32_t)
key];
1712 uint32_t hash_size = ir_hashtab_hash_size(
size);
1714 memset(
data, -1, hash_size *
sizeof(uint32_t));
1715 tab->
data = (
data + (hash_size *
sizeof(uint32_t)));
1716 tab->
mask = (uint32_t)(-(int32_t)hash_size);
1724 uint32_t hash_size = (uint32_t)(-(int32_t)tab->
mask);
1725 char *
data = (
char*)tab->
data - (hash_size *
sizeof(uint32_t));
1732 const char *
data = (
const char*)tab->
data;
1738 if (
p->key ==
key) {
1754 if (
p->key ==
key) {
1762 ir_addrtab_resize(tab);
1773 p->next = ((uint32_t*)
data)[(int32_t)
key];
1789 HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL, PAGE_EXECUTE_READWRITE, size_hi, size_lo,
NULL);
1791 ret = MapViewOfFile(h, FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE, 0, 0,
size);
1802 UnmapViewOfFile(
ptr);
1823 int prot_flags = PROT_EXEC;
1824#if defined(__NetBSD__)
1827 void *
ret = mmap(
NULL,
size, prot_flags, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1844 fprintf(stderr,
"mprotect() failed\n");
1855 fprintf(stderr,
"mprotect() failed\n");
1864#if ((defined(__GNUC__) && ZEND_GCC_VERSION >= 4003) || __has_builtin(__builtin___clear_cache))
1865 __builtin___clear_cache((
char*)(
ptr), (
char*)(
ptr) +
size);
1867#if defined(__APPLE__) && defined(__aarch64__)
1868 sys_icache_invalidate(
ptr,
size);
1871 VALGRIND_DISCARD_TRANSLATIONS(
ptr,
size);
1889 if (addr1 == addr2) {
1896 if (insn1->op1 == addr2) {
1899 }
else if (insn2->op == IR_ADD &&
IR_IS_CONST_REF(insn1->op2) && insn1->op1 == insn2->op1) {
1900 if (insn1->op2 == insn2->op2) {
1910 if (insn2->op1 == addr1) {
1923 ir_ref base1, base2, off1, off2;
1930 if (insn1->op != IR_ADD) {
1933 }
else if (ctx->
ir_base[insn1->op2].op == IR_SYM
1934 || ctx->
ir_base[insn1->op2].op == IR_ALLOCA
1935 || ctx->
ir_base[insn1->op2].op == IR_VADDR) {
1942 if (insn2->op != IR_ADD) {
1945 }
else if (ctx->
ir_base[insn2->op2].op == IR_SYM
1946 || ctx->
ir_base[insn2->op2].op == IR_ALLOCA
1947 || ctx->
ir_base[insn2->op2].op == IR_VADDR) {
1954 if (base1 == base2) {
1955 uintptr_t offset1, offset2;
1971 if (offset1 == offset2) {
1973 }
else if (offset1 < offset2) {
1981 while (insn1->op == IR_ADD) {
1982 insn1 = &ctx->
ir_base[insn1->op2];
1983 if (insn1->op == IR_SYM
1984 || insn1->op == IR_ALLOCA
1985 || insn1->op == IR_VADDR) {
1988 insn1 = &ctx->
ir_base[insn1->op1];
1991 while (insn2->op == IR_ADD) {
1992 insn2 = &ctx->
ir_base[insn2->op2];
1993 if (insn2->op == IR_SYM
1994 || insn2->op == IR_ALLOCA
1995 || insn2->op == IR_VADDR) {
1998 insn2 = &ctx->
ir_base[insn2->op1];
2001 if (insn1 == insn2) {
2004 if ((insn1->op == IR_ALLOCA && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR || insn2->op == IR_SYM || insn2->op == IR_PARAM))
2005 || (insn1->op == IR_VADDR && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR || insn2->op == IR_SYM || insn2->op == IR_PARAM))
2006 || (insn1->op == IR_SYM && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR || insn2->op == IR_SYM))
2007 || (insn1->op == IR_PARAM && (insn2->op == IR_ALLOCA || insn2->op == IR_VADDR))) {
2017 uint32_t modified_regset = 0;
2019 while (ref > limit) {
2021 if (insn->op == IR_LOAD) {
2022 if (insn->op2 ==
addr) {
2023 if (insn->type ==
type) {
2032 }
else if (insn->op == IR_STORE) {
2035 if (insn->op2 ==
addr) {
2036 if (ctx->
ir_base[insn->op3].op == IR_RLOAD
2037 && (modified_regset & (1 << ctx->
ir_base[insn->op3].op2))) {
2053 }
else if (insn->op == IR_RSTORE) {
2054 modified_regset |= (1 << insn->op3);
2055 }
else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_CALL || insn->op == IR_VSTORE) {
2075 if (insn->op == IR_VLOAD) {
2076 if (insn->op2 == var) {
2077 if (insn->type ==
type) {
2086 }
else if (insn->op == IR_VSTORE) {
2089 if (insn->op2 == var) {
2101 }
else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_CALL || insn->op == IR_STORE) {
2133 while (ref > limit) {
2135 if (insn->op == IR_STORE) {
2136 if (insn->op2 ==
addr) {
2138 if (insn->op3 ==
val) {
2177 goto check_aliasing;
2179 }
else if (insn->op == IR_LOAD) {
2180 if (insn->op2 ==
addr) {
2192 }
else if (insn->op == IR_GUARD || insn->op == IR_GUARD_NOT) {
2194 }
else if (insn->op >= IR_START || insn->op == IR_CALL) {
2226 while (ref > limit) {
2228 if (insn->op == IR_VSTORE) {
2229 if (insn->op2 == var) {
2230 if (insn->op3 ==
val) {
2265 }
else if (insn->op == IR_VLOAD) {
2266 if (insn->op2 == var) {
2273 }
else if (insn->op == IR_GUARD || insn->op == IR_GUARD_NOT) {
2275 }
else if (insn->op >= IR_START || insn->op == IR_CALL || insn->op == IR_LOAD || insn->op == IR_STORE) {
2320 if (src1 == src2 && src1 !=
IR_UNUSED) {
2341 for (i = 1; i <
n; i++) {
2342 if (inputs[i] != ref) {
2355 for (i = 0; i <
n; i++) {
2386 || ctx->
ir_base[src].op == IR_END
2387 || ctx->
ir_base[src].op == IR_LOOP_END);
2397 && ctx->
ir_base[src].op == IR_END) {
2416 if (insn->op == IR_ALLOCA || insn->op == IR_VADDR) {
2420 }
else if (insn->op == IR_EQ && insn->op2 ==
IR_TRUE) {
2423 }
else if (insn->op == IR_EQ && insn->op2 ==
IR_NULL) {
2425 if (op1_insn->op == IR_ALLOCA || op1_insn->op == IR_VADDR) {
2441 while (ref > limit) {
2443 if (insn->op == IR_GUARD_NOT) {
2444 if (insn->op2 == condition) {
2447 }
else if (insn->op == IR_GUARD) {
2448 if (insn->op2 == condition) {
2451 }
else if (insn->op == IR_IF) {
2452 if (insn->op2 == condition) {
2453 if (
prev->op == IR_IF_TRUE) {
2455 }
else if (
prev->op == IR_IF_FALSE) {
2459 }
else if (insn->op == IR_START || insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
2486 condition = _ir_fold_condition(ctx, condition);
2560 ops[
n + 1] = inputs[
n];
2570 IR_ASSERT(insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN);
2652 }
else if (!
end->op3) {
2664 for (i = 0; i < merge->inputs_count; i++) {
2791 for (i = 0; i <
count; i++) {
2941 for (i = 0; i <
count; i++) {
3045 snapshot =
ir_emit_N(ctx, IR_SNAPSHOT, 1 +
n);
3090 if (insn->type ==
type) {
3144 if (insn->type ==
type) {
fprintf($stream, string $format, mixed ... $values)
prev(array|object &$array)
fputs($stream, string $data, ?int $length=null)
count(Countable|array $value, int $mode=COUNT_NORMAL)
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
const php_stream_filter_ops * ops
void _ir_TAILCALL_4(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4)
const char * ir_get_strl(const ir_ctx *ctx, ir_ref idx, size_t *len)
ir_ref ir_addrtab_find(const ir_hashtab *tab, uint64_t key)
bool ir_use_list_add(ir_ctx *ctx, ir_ref to, ir_ref ref)
ir_ref ir_binding_find(const ir_ctx *ctx, ir_ref ref)
ir_ref ir_fold2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2)
void ir_free(ir_ctx *ctx)
ir_ref ir_str(ir_ctx *ctx, const char *s)
void ir_update_op(ir_ctx *ctx, ir_ref ref, uint32_t idx, ir_ref new_val)
void _ir_CASE_DEFAULT(ir_ctx *ctx, ir_ref switch_ref)
ir_ref ir_emit3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
ir_ref ir_const_func(ir_ctx *ctx, ir_ref str, ir_ref proto)
void _ir_IJMP(ir_ctx *ctx, ir_ref addr)
ir_ref ir_bind(ir_ctx *ctx, ir_ref var, ir_ref def)
void _ir_AFREE(ir_ctx *ctx, ir_ref size)
ir_ref ir_const_i64(ir_ctx *ctx, int64_t c)
ir_ref ir_get_op(ir_ctx *ctx, ir_ref ref, int32_t n)
ir_ref ir_fold3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
void ir_truncate(ir_ctx *ctx)
ir_ref _ir_EXITCALL(ir_ctx *ctx, ir_ref func)
void ir_list_insert(ir_list *l, uint32_t i, ir_ref val)
ir_ref _ir_IF(ir_ctx *ctx, ir_ref condition)
ir_ref ir_const_i32(ir_ctx *ctx, int32_t c)
ir_ref ir_emit2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2)
void ir_use_list_replace_one(ir_ctx *ctx, ir_ref ref, ir_ref use, ir_ref new_use)
ir_ref ir_const_addr(ir_ctx *ctx, uintptr_t c)
const char * ir_type_name[IR_LAST_TYPE]
void ir_replace(ir_ctx *ctx, ir_ref ref, ir_ref new_ref)
void _ir_TAILCALL_5(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4, ir_ref arg5)
ir_ref ir_check_dominating_predicates(ir_ctx *ctx, ir_ref ref, ir_ref condition)
ir_ref _ir_CALL_4(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4)
ir_ref ir_const_ex(ir_ctx *ctx, ir_val val, uint8_t type, uint32_t optx)
void ir_array_remove(ir_array *a, uint32_t i)
void ir_array_grow(ir_array *a, uint32_t size)
void _ir_TAILCALL_2(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2)
ir_ref _ir_ADD_OFFSET(ir_ctx *ctx, ir_ref addr, uintptr_t offset)
void _ir_SNAPSHOT_SET_OP(ir_ctx *ctx, ir_ref snapshot, ir_ref pos, ir_ref val)
ir_ref ir_const_double(ir_ctx *ctx, double c)
ir_ref _ir_BLOCK_BEGIN(ir_ctx *ctx)
void _ir_GUARD_NOT(ir_ctx *ctx, ir_ref condition, ir_ref addr)
ir_ref ir_const_bool(ir_ctx *ctx, bool c)
void ir_print_escaped_str(const char *s, size_t len, FILE *f)
void ir_build_def_use_lists(ir_ctx *ctx)
ir_ref _ir_SNAPSHOT(ir_ctx *ctx, ir_ref n)
int ir_mem_unprotect(void *ptr, size_t size)
int ir_mem_unmap(void *ptr, size_t size)
uint32_t ir_list_find(const ir_list *l, ir_ref val)
const uint8_t ir_type_flags[IR_LAST_TYPE]
void _ir_CASE_VAL(ir_ctx *ctx, ir_ref switch_ref, ir_ref val)
int ir_mem_flush(void *ptr, size_t size)
ir_ref ir_const_i8(ir_ctx *ctx, int8_t c)
void _ir_BEGIN(ir_ctx *ctx, ir_ref src)
void _ir_MERGE_2(ir_ctx *ctx, ir_ref src1, ir_ref src2)
ir_ref ir_emit1(ir_ctx *ctx, uint32_t opt, ir_ref op1)
void _ir_START(ir_ctx *ctx)
ir_ref ir_find_aliasing_load(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr)
ir_ref ir_fold(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
ir_ref ir_const_func_addr(ir_ctx *ctx, uintptr_t c, ir_ref proto)
void ir_use_list_sort(ir_ctx *ctx, ir_ref ref)
void ir_list_remove(ir_list *l, uint32_t i)
void _ir_TAILCALL_6(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4, ir_ref arg5, ir_ref arg6)
ir_ref ir_find_aliasing_vload(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var)
void _ir_TAILCALL_1(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1)
ir_ref ir_emit_N(ir_ctx *ctx, uint32_t opt, int32_t count)
ir_ref ir_const_u64(ir_ctx *ctx, uint64_t c)
const char * ir_type_cname[IR_LAST_TYPE]
ir_ref ir_unique_const_addr(ir_ctx *ctx, uintptr_t addr)
ir_ref _ir_ALLOCA(ir_ctx *ctx, ir_ref size)
void _ir_STORE(ir_ctx *ctx, ir_ref addr, ir_ref val)
#define IR_TYPE_SIZE(name, type, field, flags)
ir_ref ir_find_aliasing_vstore(ir_ctx *ctx, ir_ref ref, ir_ref var, ir_ref val)
ir_ref ir_const_i16(ir_ctx *ctx, int16_t c)
ir_ref ir_const(ir_ctx *ctx, ir_val val, uint8_t type)
void _ir_ENTRY(ir_ctx *ctx, ir_ref src, ir_ref num)
ir_ref ir_proto_5(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3, ir_type t4, ir_type t5)
void _ir_RETURN(ir_ctx *ctx, ir_ref val)
void ir_hashtab_init(ir_hashtab *tab, uint32_t size)
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vstore_i(ir_ctx *ctx, ir_ref ref, ir_ref var, ir_ref val)
void _ir_VA_COPY(ir_ctx *ctx, ir_ref dst, ir_ref src)
const char * ir_get_str(const ir_ctx *ctx, ir_ref idx)
ir_ref ir_var(ir_ctx *ctx, ir_type type, ir_ref region, const char *name)
ir_ref ir_emit(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3)
ir_ref _ir_VLOAD(ir_ctx *ctx, ir_type type, ir_ref var)
void ir_use_list_replace_all(ir_ctx *ctx, ir_ref ref, ir_ref use, ir_ref new_use)
ir_ref _ir_LOOP_BEGIN(ir_ctx *ctx, ir_ref src1)
ir_ref ir_find_aliasing_store(ir_ctx *ctx, ir_ref ref, ir_ref addr, ir_ref val)
ir_ref ir_fold1(ir_ctx *ctx, uint32_t opt, ir_ref op1)
ir_ref _ir_VAR(ir_ctx *ctx, ir_type type, const char *name)
void _ir_IF_FALSE(ir_ctx *ctx, ir_ref if_ref)
ir_ref _ir_PHI_2(ir_ctx *ctx, ir_type type, ir_ref src1, ir_ref src2)
ir_ref _ir_PHI_N(ir_ctx *ctx, ir_type type, ir_ref n, ir_ref *inputs)
ir_ref _ir_RLOAD(ir_ctx *ctx, ir_type type, ir_ref reg)
void _ir_VA_START(ir_ctx *ctx, ir_ref list)
void ir_hashtab_key_sort(ir_hashtab *tab)
ir_ref ir_const_sym(ir_ctx *ctx, ir_ref str)
ir_ref _ir_LOAD(ir_ctx *ctx, ir_type type, ir_ref addr)
ir_alias ir_check_partial_aliasing(const ir_ctx *ctx, ir_ref addr1, ir_ref addr2, ir_type type1, ir_type type2)
ir_ref ir_strl(ir_ctx *ctx, const char *s, size_t len)
const uint32_t ir_op_flags[IR_LAST_OP]
void ir_set_op(ir_ctx *ctx, ir_ref ref, int32_t n, ir_ref val)
void ir_use_list_remove_one(ir_ctx *ctx, ir_ref from, ir_ref ref)
void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted)
ir_ref _ir_CALL_1(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1)
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vload_i(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var)
ir_ref _ir_TLS(ir_ctx *ctx, ir_ref index, ir_ref offset)
void ir_init(ir_ctx *ctx, uint32_t flags, ir_ref consts_limit, ir_ref insns_limit)
void _ir_VA_END(ir_ctx *ctx, ir_ref list)
void _ir_TAILCALL(ir_ctx *ctx, ir_type type, ir_ref func)
ir_ref ir_proto_2(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2)
ir_ref _ir_PHI_LIST(ir_ctx *ctx, ir_ref list)
ir_ref ir_proto(ir_ctx *ctx, uint8_t flags, ir_type ret_type, uint32_t params_count, uint8_t *param_types)
ir_ref ir_const_u8(ir_ctx *ctx, uint8_t c)
ir_ref ir_const_u32(ir_ctx *ctx, uint32_t c)
#define IR_TYPE_FLAGS(name, type, field, flags)
int ir_mem_protect(void *ptr, size_t size)
IR_ALWAYS_INLINE ir_ref ir_check_dominating_predicates_i(ir_ctx *ctx, ir_ref ref, ir_ref condition, ir_ref limit)
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_load_i(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr, ir_ref limit)
void ir_use_list_remove_all(ir_ctx *ctx, ir_ref from, ir_ref ref)
const char * ir_op_name[IR_LAST_OP]
#define IR_OP_NAME(name, flags, op1, op2, op3)
void _ir_GUARD(ir_ctx *ctx, ir_ref condition, ir_ref addr)
ir_ref ir_folding(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3, ir_insn *op1_insn, ir_insn *op2_insn, ir_insn *op3_insn)
ir_ref ir_const_float(ir_ctx *ctx, float c)
ir_ref _ir_CALL_N(ir_ctx *ctx, ir_type type, ir_ref func, uint32_t count, ir_ref *args)
ir_ref _ir_SWITCH(ir_ctx *ctx, ir_ref val)
ir_ref _ir_VA_ARG(ir_ctx *ctx, ir_type type, ir_ref list)
#define _IR_OP_FLAGS(name, flags, op1, op2, op3)
void _ir_IF_FALSE_cold(ir_ctx *ctx, ir_ref if_ref)
ir_ref ir_proto_0(ir_ctx *ctx, uint8_t flags, ir_type ret_type)
ir_ref ir_param(ir_ctx *ctx, ir_type type, ir_ref region, const char *name, int pos)
void ir_array_insert(ir_array *a, uint32_t i, ir_ref val)
ir_ref _ir_LOOP_END(ir_ctx *ctx)
void ir_addrtab_init(ir_hashtab *tab, uint32_t size)
void _ir_MERGE_LIST(ir_ctx *ctx, ir_ref list)
ir_ref _ir_CALL(ir_ctx *ctx, ir_type type, ir_ref func)
void _ir_TAILCALL_N(ir_ctx *ctx, ir_type type, ir_ref func, uint32_t count, ir_ref *args)
void _ir_PHI_SET_OP(ir_ctx *ctx, ir_ref phi, ir_ref pos, ir_ref src)
ir_ref ir_proto_1(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1)
ir_ref ir_const_str(ir_ctx *ctx, ir_ref str)
ir_ref ir_const_char(ir_ctx *ctx, char c)
const uint8_t ir_type_size[IR_LAST_TYPE]
ir_ref _ir_CALL_5(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4, ir_ref arg5)
ir_ref _ir_PARAM(ir_ctx *ctx, ir_type type, const char *name, ir_ref num)
void _ir_MERGE_N(ir_ctx *ctx, ir_ref n, ir_ref *inputs)
void ir_hashtab_free(ir_hashtab *tab)
void _ir_VSTORE(ir_ctx *ctx, ir_ref var, ir_ref val)
ir_ref _ir_CALL_3(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3)
IR_ALWAYS_INLINE ir_ref ir_find_aliasing_store_i(ir_ctx *ctx, ir_ref ref, ir_ref addr, ir_ref val, ir_ref limit)
ir_ref ir_proto_4(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3, ir_type t4)
ir_ref _ir_CALL_2(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2)
ir_ref ir_const_u16(ir_ctx *ctx, uint16_t c)
void ir_addrtab_set(ir_hashtab *tab, uint64_t key, ir_ref val)
void ir_addrtab_free(ir_hashtab *tab)
void _ir_MERGE_SET_OP(ir_ctx *ctx, ir_ref merge, ir_ref pos, ir_ref src)
ir_ref ir_hashtab_find(const ir_hashtab *tab, uint32_t key)
void _ir_TAILCALL_3(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3)
void * ir_mem_mmap(size_t size)
void _ir_RSTORE(ir_ctx *ctx, ir_ref reg, ir_ref val)
void _ir_IF_TRUE_cold(ir_ctx *ctx, ir_ref if_ref)
ir_ref ir_fold0(ir_ctx *ctx, uint32_t opt)
ir_ref _ir_END_LIST(ir_ctx *ctx, ir_ref list)
ir_ref _ir_END(ir_ctx *ctx)
void _ir_IF_TRUE(ir_ctx *ctx, ir_ref if_ref)
#define IR_TYPE_NAME(name, type, field, flags)
ir_ref _ir_CALL_6(ir_ctx *ctx, ir_type type, ir_ref func, ir_ref arg1, ir_ref arg2, ir_ref arg3, ir_ref arg4, ir_ref arg5, ir_ref arg6)
#define IR_TYPE_CNAME(name, type, field, flags)
bool ir_hashtab_add(ir_hashtab *tab, uint32_t key, ir_ref val)
ir_ref _ir_END_PHI_LIST(ir_ctx *ctx, ir_ref list, ir_ref val)
ir_ref ir_proto_3(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3)
ir_ref ir_emit0(ir_ctx *ctx, uint32_t opt)
void _ir_UNREACHABLE(ir_ctx *ctx)
const char * ir_strtab_strl(const ir_strtab *strtab, ir_ref idx, size_t *len)
#define IR_OPTX(op, type, n)
#define IR_IS_TYPE_INT(t)
IR_ALWAYS_INLINE uint32_t ir_insn_find_op(const ir_insn *insn, ir_ref val)
struct _ir_hashtab ir_hashtab
#define ir_strtab_count(strtab)
IR_ALWAYS_INLINE ir_ref ir_insn_op(const ir_insn *insn, int32_t n)
struct _ir_proto_t ir_proto_t
#define IR_IS_CONST_REF(ref)
IR_ALWAYS_INLINE void ir_insn_set_op(ir_insn *insn, int32_t n, ir_ref val)
const char * ir_strtab_str(const ir_strtab *strtab, ir_ref idx)
ir_ref ir_strtab_lookup(ir_strtab *strtab, const char *str, uint32_t len, ir_ref val)
void ir_strtab_free(ir_strtab *strtab)
#define IR_INSNS_LIMIT_MIN
#define IR_MAX_PROTO_PARAMS
#define IR_CONSTS_LIMIT_MIN
#define IR_OPT_INPUTS_SHIFT
void ir_strtab_init(ir_strtab *strtab, uint32_t count, uint32_t buf_size)
struct _ir_use_list ir_use_list
#define IR_IS_CONST_OP(op)
#define IR_ALIGNED_SIZE(size, alignment)
struct _ir_addrtab_bucket ir_addrtab_bucket
struct _ir_hashtab_bucket ir_hashtab_bucket
#define IR_IS_SYM_CONST(op)
#define IR_IS_BB_START(op)
IR_ALWAYS_INLINE void ir_list_free(ir_list *l)
IR_ALWAYS_INLINE uint32_t ir_insn_inputs_to_len(uint32_t inputs_count)
#define IR_INPUT_EDGES_COUNT(flags)
IR_ALWAYS_INLINE ir_ref ir_array_at(const ir_array *a, uint32_t i)
IR_ALWAYS_INLINE void ir_arena_free(ir_arena *arena)
IR_ALWAYS_INLINE bool ir_ref_is_true(ir_ctx *ctx, ir_ref ref)
#define IR_OP_FLAG_TERMINATOR
struct _ir_array ir_array
#define IR_OP_HAS_VAR_INPUTS(flags)
unsigned const char * end
unsigned const char * pos
#define offsetof(STRUCTURE, FIELD)
unsigned char key[REFLECTION_KEY_LEN]
int mprotect(void *addr, size_t size, int protection)
ir_live_interval ** live_intervals
ir_ref prev_const_chain[IR_LAST_TYPE]
int32_t fixed_stack_frame_size
ir_snapshot_create_t snapshot_create
ir_ref prev_insn_chain[IR_LAST_FOLDABLE_OP+1]
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
#define EXPECTED(condition)
#define UNEXPECTED(condition)