mirror of
https://github.com/danog/ir.git
synced 2025-01-22 05:31:32 +01:00
Initial support for PHP
This commit is contained in:
parent
63ec9b4864
commit
5cafe50d36
38
ir.c
38
ir.c
@ -41,6 +41,9 @@ const char *ir_type_cname[IR_LAST_TYPE] = {
|
||||
|
||||
const char *ir_op_name[IR_LAST_OP] = {
|
||||
IR_OPS(IR_OP_NAME)
|
||||
#ifdef IR_PHP
|
||||
IR_PHP_OPS(IR_OP_NAME)
|
||||
#endif
|
||||
};
|
||||
|
||||
void ir_print_const(ir_ctx *ctx, ir_insn *insn, FILE *f)
|
||||
@ -70,7 +73,11 @@ void ir_print_const(ir_ctx *ctx, ir_insn *insn, FILE *f)
|
||||
fprintf(f, "%" PRIu64, insn->val.u64);
|
||||
break;
|
||||
case IR_ADDR:
|
||||
fprintf(f, "%" PRIxPTR, insn->val.addr);
|
||||
if (insn->val.addr) {
|
||||
fprintf(f, "0x%" PRIxPTR, insn->val.addr);
|
||||
} else {
|
||||
fprintf(f, "0");
|
||||
}
|
||||
break;
|
||||
case IR_CHAR:
|
||||
if (insn->val.c == '\\') {
|
||||
@ -136,14 +143,39 @@ void ir_print_const(ir_ctx *ctx, ir_insn *insn, FILE *f)
|
||||
#define ir_op_flag_c0X2 (ir_op_flag_c | 0 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_c1 (ir_op_flag_c | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_c1X1 (ir_op_flag_c | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_c1X2 (ir_op_flag_c | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_c2 (ir_op_flag_c | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_c2X1 (ir_op_flag_c | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_c3 (ir_op_flag_c | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_cN (ir_op_flag_c | 4 | (4 << IR_OP_FLAG_OPERANDS_SHIFT)) // MERGE (number of operands encoded in op1)
|
||||
#define ir_op_flag_B (IR_OP_FLAG_CONTROL|IR_OP_FLAG_BB_BEGIN)
|
||||
#define ir_op_flag_B0 ir_op_flag_B
|
||||
#define ir_op_flag_B0X1 (ir_op_flag_B | 0 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_B0X2 (ir_op_flag_B | 0 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_B1 (ir_op_flag_B | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_B1X1 (ir_op_flag_B | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_B1X2 (ir_op_flag_B | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_B2 (ir_op_flag_B | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_B2X1 (ir_op_flag_B | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_B3 (ir_op_flag_B | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_BN (ir_op_flag_B | 4 | (4 << IR_OP_FLAG_OPERANDS_SHIFT)) // MERGE (number of operands encoded in op1)
|
||||
#define ir_op_flag_E (IR_OP_FLAG_CONTROL|IR_OP_FLAG_BB_END)
|
||||
#define ir_op_flag_E0 ir_op_flag_B
|
||||
#define ir_op_flag_E0X1 (ir_op_flag_E | 0 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_E0X2 (ir_op_flag_E | 0 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_E1 (ir_op_flag_E | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_E1X1 (ir_op_flag_E | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_E1X2 (ir_op_flag_E | 1 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_E2 (ir_op_flag_E | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_E2X1 (ir_op_flag_E | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_E3 (ir_op_flag_E | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_EN (ir_op_flag_E | 4 | (4 << IR_OP_FLAG_OPERANDS_SHIFT)) // MERGE (number of operands encoded in op1)
|
||||
#define ir_op_flag_l (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_LOAD)
|
||||
#define ir_op_flag_l0 ir_op_flag_l
|
||||
#define ir_op_flag_l1 (ir_op_flag_l | 1 | (1 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_l1X1 (ir_op_flag_l | 1 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_l2 (ir_op_flag_l | 2 | (2 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_l2X1 (ir_op_flag_l | 2 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_l3 (ir_op_flag_l | 3 | (3 << IR_OP_FLAG_OPERANDS_SHIFT))
|
||||
#define ir_op_flag_s (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_STORE)
|
||||
#define ir_op_flag_s0 ir_op_flag_s
|
||||
@ -160,6 +192,7 @@ void ir_print_const(ir_ctx *ctx, ir_insn *insn, FILE *f)
|
||||
#define ir_op_kind_reg IR_OPND_CONTROL_DEP
|
||||
#define ir_op_kind_beg IR_OPND_CONTROL_REF
|
||||
#define ir_op_kind_ret IR_OPND_CONTROL_REF
|
||||
#define ir_op_kind_ent IR_OPND_CONTROL_REF
|
||||
#define ir_op_kind_str IR_OPND_STR
|
||||
#define ir_op_kind_num IR_OPND_NUM
|
||||
#define ir_op_kind_fld IR_OPND_STR
|
||||
@ -171,6 +204,9 @@ void ir_print_const(ir_ctx *ctx, ir_insn *insn, FILE *f)
|
||||
|
||||
const uint32_t ir_op_flags[IR_LAST_OP] = {
|
||||
IR_OPS(_IR_OP_FLAGS)
|
||||
#ifdef IR_PHP
|
||||
IR_PHP_OPS(_IR_OP_FLAGS)
|
||||
#endif
|
||||
};
|
||||
|
||||
static void ir_grow_bottom(ir_ctx *ctx)
|
||||
|
43
ir.h
43
ir.h
@ -3,6 +3,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define IR_VERSION "0.0.1"
|
||||
@ -43,7 +44,9 @@
|
||||
# error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
typedef uint8_t bool;
|
||||
#ifdef IR_PHP
|
||||
# include "ir_php.h"
|
||||
#endif
|
||||
|
||||
/* IR Type flags (low 4 bits are used for type size) */
|
||||
#define IR_TYPE_SIGNED (1<<4)
|
||||
@ -94,6 +97,8 @@ typedef enum _ir_type {
|
||||
* d - data IR_OP_FLAG_DATA
|
||||
* r - ref IR_OP_FLAG_DATA alias
|
||||
* c - control IR_OP_FLAG_CONTROL
|
||||
* B - control IR_OP_FLAG_CONTROL + IR_OP_FLAG_BB_BEGIN
|
||||
* E - control IR_OP_FLAG_CONTROL + IR_OP_FLAG_BB_END
|
||||
* l - load IR_OP_FLAG_MEM + IR_OP_FLAG_MEM_LOAD
|
||||
* s - store IR_OP_FLAG_MEM + IR_OP_FLAG_STORE
|
||||
* x - call IR_OP_FLAG_MEM + IR_OP_FLAG_CALL
|
||||
@ -115,6 +120,7 @@ typedef enum _ir_type {
|
||||
* reg - data-control dependency on region (PHI, VAR, PARAM)
|
||||
* beg - reference to a LOOP_BEGIN region (LOOP_END, LOOP_EXIT)
|
||||
* ret - reference to a previous RETURN instruction (RETURN)
|
||||
* ent - reference to a previous ENTRY instruction (ENTRY)
|
||||
* str - string: variable/argument name (VAR, PARAM, CALL, TAILCALL)
|
||||
* num - number: argument number (PARAM)
|
||||
* prb - branch probability 1-99 (0 - unspecified): (IF_TRUE, IF_FALSE, CASE_VAL, CASE_DEFAULT)
|
||||
@ -223,27 +229,29 @@ typedef enum _ir_type {
|
||||
_(VADDR, d1, var, ___, ___) /* load address of local var */ \
|
||||
_(VLOAD, l2, src, var, ___) /* load value of local var */ \
|
||||
_(VSTORE, s3, src, var, def) /* store value to local var */ \
|
||||
_(RLOAD, l1X1, src, num, ___) /* load value from register */ \
|
||||
_(RSTORE, l2X1, src, def, num) /* store value into register */ \
|
||||
_(LOAD, l2, src, ref, ___) /* load from memory */ \
|
||||
_(STORE, s3, src, ref, def) /* store to memory */ \
|
||||
/* memory reference ops (A, H, U, S, TMP, STR, NEW, X, V) ??? */ \
|
||||
\
|
||||
/* control-flow nodes */ \
|
||||
_(START, c0X1, ret, ___, ___) /* function start */ \
|
||||
_(RETURN, c2X1, src, def, ret) /* function return */ \
|
||||
_(UNREACHABLE, c2X1, src, def, ret) /* unreachable (tailcall, etc) */ \
|
||||
_(BEGIN, c1, src, ___, ___) /* block start */ \
|
||||
_(END, c1, src, ___, ___) /* block end */ \
|
||||
_(IF, c2, src, def, ___) /* conditional control split */ \
|
||||
_(IF_TRUE, c1X1, src, prb, ___) /* IF TRUE proj. */ \
|
||||
_(IF_FALSE, c1X1, src, prb, ___) /* IF FALSE proj. */ \
|
||||
_(SWITCH, c2, src, def, ___) /* multi-way control split */ \
|
||||
_(CASE_VAL, c2X1, src, def, prb) /* switch proj. */ \
|
||||
_(CASE_DEFAULT, c1X1, src, prb, ___) /* switch proj. */ \
|
||||
_(MERGE, cN, src, src, src) /* control merge */ \
|
||||
_(LOOP_BEGIN, c2, src, src, ___) /* loop start */ \
|
||||
_(LOOP_END, c1X1, src, beg, ___) /* loop end */ \
|
||||
_(START, B0X2, ret, ent, ___) /* function start */ \
|
||||
_(RETURN, E2X1, src, def, ret) /* function return */ \
|
||||
_(UNREACHABLE, E2X1, src, def, ret) /* unreachable (tailcall, etc) */ \
|
||||
_(BEGIN, B1, src, ___, ___) /* block start */ \
|
||||
_(END, E1, src, ___, ___) /* block end */ \
|
||||
_(IF, E2, src, def, ___) /* conditional control split */ \
|
||||
_(IF_TRUE, B1X1, src, prb, ___) /* IF TRUE proj. */ \
|
||||
_(IF_FALSE, B1X1, src, prb, ___) /* IF FALSE proj. */ \
|
||||
_(SWITCH, E2, src, def, ___) /* multi-way control split */ \
|
||||
_(CASE_VAL, B2X1, src, def, prb) /* switch proj. */ \
|
||||
_(CASE_DEFAULT, B1X1, src, prb, ___) /* switch proj. */ \
|
||||
_(MERGE, BN, src, src, src) /* control merge */ \
|
||||
_(LOOP_BEGIN, B2, src, src, ___) /* loop start */ \
|
||||
_(LOOP_END, E1X1, src, beg, ___) /* loop end */ \
|
||||
_(LOOP_EXIT, c1X1, src, beg, ___) /* loop exit */ \
|
||||
_(IJMP, c2X1, src, def, ret) /* computed goto */ \
|
||||
_(IJMP, E2X1, src, def, ret) /* computed goto */ \
|
||||
\
|
||||
/* guards (floating or not) ??? */ \
|
||||
_(GUARD_TRUE, c2, src, def, ___) /* IF without second successor */ \
|
||||
@ -253,6 +261,9 @@ typedef enum _ir_type {
|
||||
|
||||
typedef enum _ir_op {
|
||||
IR_OPS(IR_OP_ENUM)
|
||||
#ifdef IR_PHP
|
||||
IR_PHP_OPS(IR_OP_ENUM)
|
||||
#endif
|
||||
IR_LAST_OP
|
||||
} ir_op;
|
||||
|
||||
|
@ -405,6 +405,7 @@ uint8_t ir_get_use_flags(ir_ctx *ctx, ir_ref ref, int op_num)
|
||||
case IR_BITCAST:
|
||||
case IR_RETURN_INT:
|
||||
case IR_RETURN_FP:
|
||||
case IR_RSTORE:
|
||||
case IR_SKIP_REG: /* PARAM PHI PI */
|
||||
return IR_USE_SHOULD_BE_IN_REG;
|
||||
}
|
||||
@ -856,6 +857,7 @@ binop_fp:
|
||||
case IR_PHI:
|
||||
case IR_PI:
|
||||
case IR_PARAM:
|
||||
case IR_RLOAD:
|
||||
return IR_SKIP_REG;
|
||||
|
||||
case IR_CALL:
|
||||
@ -2934,6 +2936,28 @@ static void ir_emit_store_fp(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
|
||||
ir_emit_store_mem_fp(ctx, type, op2_reg, 0, op3_reg);
|
||||
}
|
||||
|
||||
static void ir_emit_rstore(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
|
||||
{
|
||||
ir_ref type = ctx->ir_base[insn->op2].type;
|
||||
ir_reg op2_reg = ctx->regs[ref][2];
|
||||
ir_reg dst_reg = insn->op3;
|
||||
|
||||
if (op2_reg != IR_REG_NONE) {
|
||||
if (op2_reg & IR_REG_SPILL_LOAD) {
|
||||
op2_reg &= ~IR_REG_SPILL_LOAD;
|
||||
ir_emit_load(ctx, type, op2_reg, insn->op2);
|
||||
}
|
||||
if (IR_IS_TYPE_INT(type)) {
|
||||
ir_emit_mov(ctx, type, dst_reg, op2_reg);
|
||||
} else {
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
ir_emit_fp_mov(ctx, type, dst_reg, op2_reg);
|
||||
}
|
||||
} else {
|
||||
ir_emit_load(ctx, type, dst_reg, insn->op2);
|
||||
}
|
||||
}
|
||||
|
||||
static void ir_emit_alloca(ir_ctx *ctx, ir_ref def, ir_insn *insn)
|
||||
{
|
||||
ir_backend_data *data = ctx->data;
|
||||
@ -3445,8 +3469,15 @@ static void ir_emit_call(ir_ctx *ctx, ir_ref def, ir_insn *insn)
|
||||
int32_t used_stack = ir_emit_arguments(ctx, def, insn, ctx->regs[def][1]);
|
||||
|
||||
if (IR_IS_CONST_REF(insn->op2)) {
|
||||
const char *name = ir_get_str(ctx, ctx->ir_base[insn->op2].val.addr);
|
||||
void *addr = ir_resolve_sym_name(name);
|
||||
ir_insn *addr_insn = &ctx->ir_base[insn->op2];
|
||||
void *addr;
|
||||
|
||||
IR_ASSERT(addr_insn->type == IR_ADDR);
|
||||
if (addr_insn->op == IR_FUNC) {
|
||||
addr = ir_resolve_sym_name(ir_get_str(ctx, addr_insn->val.addr));
|
||||
} else {
|
||||
addr = (void*)addr_insn->val.addr;
|
||||
}
|
||||
|
||||
| bl &addr
|
||||
} else {
|
||||
@ -3507,8 +3538,15 @@ static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn)
|
||||
ir_emit_epilogue(ctx);
|
||||
|
||||
if (IR_IS_CONST_REF(insn->op2)) {
|
||||
const char *name = ir_get_str(ctx, ctx->ir_base[insn->op2].val.addr);
|
||||
void *addr = ir_resolve_sym_name(name);
|
||||
ir_insn *addr_insn = &ctx->ir_base[insn->op2];
|
||||
void *addr;
|
||||
|
||||
IR_ASSERT(addr_insn->type == IR_ADDR);
|
||||
if (addr_insn->op == IR_FUNC) {
|
||||
addr = ir_resolve_sym_name(ir_get_str(ctx, addr_insn->val.addr));
|
||||
} else {
|
||||
addr = (void*)addr_insn->val.addr;
|
||||
}
|
||||
|
||||
| b &addr
|
||||
} else {
|
||||
@ -4321,6 +4359,9 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size)
|
||||
case IR_VSTORE:
|
||||
ir_emit_vstore(ctx, i, insn);
|
||||
break;
|
||||
case IR_RSTORE:
|
||||
ir_emit_rstore(ctx, i, insn);
|
||||
break;
|
||||
case IR_LOAD_INT:
|
||||
ir_emit_load_int(ctx, i, insn);
|
||||
break;
|
||||
|
4
ir_cfg.c
4
ir_cfg.c
@ -29,7 +29,7 @@ int ir_build_cfg(ir_ctx *ctx)
|
||||
while (1) {
|
||||
insn = &ctx->ir_base[ref];
|
||||
_blocks[ref] = bb_count;
|
||||
if (IR_IS_BB_START(insn->op)) {
|
||||
if (IR_IS_BB_BEGIN(insn->op)) {
|
||||
ir_bitset_incl(worklist.visited, ref);
|
||||
break;
|
||||
}
|
||||
@ -62,7 +62,7 @@ int ir_build_cfg(ir_ctx *ctx)
|
||||
_blocks[ref] = n;
|
||||
bb = &blocks[n];
|
||||
insn = &ctx->ir_base[ref];
|
||||
if (IR_IS_BB_START(insn->op)) {
|
||||
if (IR_IS_BB_BEGIN(insn->op)) {
|
||||
bb->start = ref;
|
||||
} else {
|
||||
bb->end = ref;
|
||||
|
@ -397,7 +397,7 @@ int main(int argc, char **argv)
|
||||
|
||||
ir_perf_map_register("test", entry, size);
|
||||
ir_perf_jitdump_open();
|
||||
ir_perf_jitdump_register("test", entry, size);
|
||||
ir_perf_jitdump_register("test", entry, size);
|
||||
|
||||
ir_mem_unprotect(entry, 4096);
|
||||
ir_gdb_register("test", entry, size, 0, 0);
|
||||
|
23
ir_php.h
Normal file
23
ir_php.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef IR_PHP_H
|
||||
#define IR_PHP_H
|
||||
|
||||
#define IR_PHP_OPS(_) \
|
||||
_(PHP_ENTRY, B0X2, num, ent, ___) /* PHP Code Entry */ \
|
||||
|
||||
#if defined(IR_TARGET_X86)
|
||||
# define IR_REG_PHP_FP IR_REG_RSI
|
||||
# define IR_REG_PHP_IP IR_REG_RDI
|
||||
#elif defined(IR_TARGET_X64)
|
||||
# define IR_REG_PHP_FP IR_REG_R14
|
||||
# define IR_REG_PHP_IP IR_REG_R15
|
||||
#elif defined(IR_TARGET_AARCH64)
|
||||
# define IR_REG_PHP_FP IR_REG_X27
|
||||
# define IR_REG_PHP_IP IR_REG_X28
|
||||
#else
|
||||
# error "Unknown IR target"
|
||||
#endif
|
||||
|
||||
#define IR_REGSET_PHP_FIXED \
|
||||
(IR_REGSET(IR_REG_PHP_FP) | IR_REGSET(IR_REG_PHP_IP))
|
||||
|
||||
#endif /* IR_PHP_H */
|
11
ir_private.h
11
ir_private.h
@ -544,6 +544,8 @@ extern const char *ir_op_name[IR_LAST_OP];
|
||||
#define IR_OP_FLAG_CONTROL (1<<9)
|
||||
#define IR_OP_FLAG_MEM (1<<10)
|
||||
#define IR_OP_FLAG_COMMUTATIVE (1<<11)
|
||||
#define IR_OP_FLAG_BB_BEGIN (1<<12)
|
||||
#define IR_OP_FLAG_BB_END (1<<13)
|
||||
|
||||
#define IR_OP_FLAG_MEM_LOAD ((0<<6)|(0<<7))
|
||||
#define IR_OP_FLAG_MEM_STORE ((0<<6)|(1<<7))
|
||||
@ -616,16 +618,14 @@ struct _ir_use_list {
|
||||
};
|
||||
|
||||
/*** IR Basic Blocks info ***/
|
||||
#define IR_IS_BB_START(op) \
|
||||
((op) == IR_START || (op) == IR_BEGIN || (op) == IR_MERGE || (op) == IR_LOOP_BEGIN || \
|
||||
(op) == IR_IF_TRUE || (op) == IR_IF_FALSE || (op) == IR_CASE_VAL || (op) == IR_CASE_DEFAULT)
|
||||
#define IR_IS_BB_BEGIN(op) \
|
||||
((ir_op_flags[op] & IR_OP_FLAG_BB_BEGIN) != 0)
|
||||
|
||||
#define IR_IS_BB_MERGE(op) \
|
||||
((op) == IR_MERGE || (op) == IR_LOOP_BEGIN)
|
||||
|
||||
#define IR_IS_BB_END(op) \
|
||||
((op) == IR_RETURN || (op) == IR_END || (op) == IR_LOOP_END || (op) == IR_IF || \
|
||||
(op) == IR_SWITCH || (op) == IR_IJMP || (op) == IR_UNREACHABLE)
|
||||
((ir_op_flags[op] & IR_OP_FLAG_BB_END) != 0)
|
||||
|
||||
#define IR_BB_UNREACHABLE (1<<0)
|
||||
#define IR_BB_LOOP_HEADER (1<<1)
|
||||
@ -723,6 +723,7 @@ struct _ir_live_range {
|
||||
#define IR_LIVE_INTERVAL_HAS_HINTS (1<<6)
|
||||
#define IR_LIVE_INTERVAL_MEM_PARAM (1<<7)
|
||||
#define IR_LIVE_INTERVAL_MEM_LOAD (1<<8)
|
||||
#define IR_LIVE_INTERVAL_REG_LOAD (1<<9)
|
||||
|
||||
struct _ir_live_interval {
|
||||
uint8_t type;
|
||||
|
9
ir_ra.c
9
ir_ra.c
@ -406,7 +406,12 @@ int ir_compute_live_ranges(ir_ctx *ctx)
|
||||
if ((flags & IR_OP_FLAG_DATA) || ((flags & IR_OP_FLAG_MEM) && insn->type != IR_VOID)) {
|
||||
if (ctx->vregs[i]) {
|
||||
if (ir_bitset_in(live, ctx->vregs[i])) {
|
||||
if (insn->op != IR_PHI) {
|
||||
if (insn->op == IR_RLOAD) {
|
||||
ir_fix_live_range(ctx, ctx->vregs[i],
|
||||
IR_START_LIVE_POS_FROM_REF(bb->start), IR_DEF_LIVE_POS_FROM_REF(i));
|
||||
ctx->live_intervals[ctx->vregs[i]]->flags = IR_LIVE_INTERVAL_REG_LOAD;
|
||||
ctx->live_intervals[ctx->vregs[i]]->reg = insn->op2;
|
||||
} else if (insn->op != IR_PHI) {
|
||||
ir_live_pos def_pos;
|
||||
ir_ref hint_ref = 0;
|
||||
|
||||
@ -2051,6 +2056,8 @@ static int ir_linear_scan(ir_ctx *ctx)
|
||||
if (ival->stack_spill_pos == -1) {
|
||||
ival->stack_spill_pos = ir_allocate_spill_slot(ctx, ival->type, &data);
|
||||
}
|
||||
} else if (ival->flags & IR_LIVE_INTERVAL_REG_LOAD) {
|
||||
/* pre-allocated fixed register */
|
||||
} else if (!(ival->flags & (IR_LIVE_INTERVAL_MEM_PARAM|IR_LIVE_INTERVAL_MEM_LOAD))
|
||||
|| !ir_ival_spill_for_fuse_load(ctx, ival, &data)) {
|
||||
ir_add_to_unhandled(&unhandled, ival);
|
||||
|
55
ir_x86.dasc
55
ir_x86.dasc
@ -875,6 +875,7 @@ uint8_t ir_get_use_flags(ir_ctx *ctx, ir_ref ref, int op_num)
|
||||
case IR_RETURN_INT:
|
||||
case IR_RETURN_FP:
|
||||
case IR_IJMP:
|
||||
case IR_RSTORE:
|
||||
case IR_SKIP_REG: /* PARAM PHI PI */
|
||||
return IR_USE_SHOULD_BE_IN_REG;
|
||||
// case IR_VLOAD:
|
||||
@ -1414,6 +1415,7 @@ binop_fp:
|
||||
case IR_PHI:
|
||||
case IR_PI:
|
||||
case IR_PARAM:
|
||||
case IR_RLOAD:
|
||||
return IR_SKIP_REG;
|
||||
|
||||
case IR_CALL:
|
||||
@ -3411,7 +3413,9 @@ static void ir_emit_return_void(ir_ctx *ctx)
|
||||
ir_backend_data *data = ctx->data;
|
||||
dasm_State **Dst = &data->dasm_state;
|
||||
|
||||
ir_emit_epilogue(ctx);
|
||||
if (ctx->flags & IR_FUNCTION) {
|
||||
ir_emit_epilogue(ctx);
|
||||
}
|
||||
| ret
|
||||
}
|
||||
|
||||
@ -4324,6 +4328,28 @@ static void ir_emit_store_fp(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
|
||||
ir_emit_store_mem_fp(ctx, type, op2_reg, 0, op3_reg);
|
||||
}
|
||||
|
||||
static void ir_emit_rstore(ir_ctx *ctx, ir_ref ref, ir_insn *insn)
|
||||
{
|
||||
ir_ref type = ctx->ir_base[insn->op2].type;
|
||||
ir_reg op2_reg = ctx->regs[ref][2];
|
||||
ir_reg dst_reg = insn->op3;
|
||||
|
||||
if (op2_reg != IR_REG_NONE) {
|
||||
if (op2_reg & IR_REG_SPILL_LOAD) {
|
||||
op2_reg &= ~IR_REG_SPILL_LOAD;
|
||||
ir_emit_load(ctx, type, op2_reg, insn->op2);
|
||||
}
|
||||
if (IR_IS_TYPE_INT(type)) {
|
||||
ir_emit_mov(ctx, type, dst_reg, op2_reg);
|
||||
} else {
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
ir_emit_fp_mov(ctx, type, dst_reg, op2_reg);
|
||||
}
|
||||
} else {
|
||||
ir_emit_load(ctx, type, dst_reg, insn->op2);
|
||||
}
|
||||
}
|
||||
|
||||
static void ir_emit_alloca(ir_ctx *ctx, ir_ref def, ir_insn *insn)
|
||||
{
|
||||
ir_backend_data *data = ctx->data;
|
||||
@ -4941,9 +4967,15 @@ static void ir_emit_call(ir_ctx *ctx, ir_ref def, ir_insn *insn)
|
||||
int32_t used_stack = ir_emit_arguments(ctx, def, insn, ctx->regs[def][1]);
|
||||
|
||||
if (IR_IS_CONST_REF(insn->op2)) {
|
||||
const char *name = ir_get_str(ctx, ctx->ir_base[insn->op2].val.addr);
|
||||
void *addr = ir_resolve_sym_name(name);
|
||||
ir_insn *addr_insn = &ctx->ir_base[insn->op2];
|
||||
void *addr;
|
||||
|
||||
IR_ASSERT(addr_insn->type == IR_ADDR);
|
||||
if (addr_insn->op == IR_FUNC) {
|
||||
addr = ir_resolve_sym_name(ir_get_str(ctx, addr_insn->val.addr));
|
||||
} else {
|
||||
addr = (void*)addr_insn->val.addr;
|
||||
}
|
||||
if (sizeof(void*) == 4 /*|| IR_IS_SIGNED_32BIT(addr)*/) { // TODO: 32-bit IP relative or 64-bit absolute address
|
||||
| call aword &addr
|
||||
} else {
|
||||
@ -5016,12 +5048,20 @@ static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn)
|
||||
|
||||
IR_ASSERT(used_stack == 0);
|
||||
|
||||
ir_emit_epilogue(ctx);
|
||||
if (ctx->flags & IR_FUNCTION) {
|
||||
ir_emit_epilogue(ctx);
|
||||
}
|
||||
|
||||
if (IR_IS_CONST_REF(insn->op2)) {
|
||||
const char *name = ir_get_str(ctx, ctx->ir_base[insn->op2].val.addr);
|
||||
void *addr = ir_resolve_sym_name(name);
|
||||
ir_insn *addr_insn = &ctx->ir_base[insn->op2];
|
||||
void *addr;
|
||||
|
||||
IR_ASSERT(addr_insn->type == IR_ADDR);
|
||||
if (addr_insn->op == IR_FUNC) {
|
||||
addr = ir_resolve_sym_name(ir_get_str(ctx, addr_insn->val.addr));
|
||||
} else {
|
||||
addr = (void*)addr_insn->val.addr;
|
||||
}
|
||||
if (sizeof(void*) == 4 /*|| IR_IS_SIGNED_32BIT(addr)*/) { // TODO: 32-bit IP relative or 64-bit absolute address
|
||||
| jmp aword &addr
|
||||
} else {
|
||||
@ -6363,6 +6403,9 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size)
|
||||
case IR_VSTORE_FP:
|
||||
ir_emit_vstore_fp(ctx, i, insn);
|
||||
break;
|
||||
case IR_RSTORE:
|
||||
ir_emit_rstore(ctx, i, insn);
|
||||
break;
|
||||
case IR_LOAD_INT:
|
||||
ir_emit_load_int(ctx, i, insn);
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user