mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
@@ -539,38 +539,38 @@ void ir_strtab_apply(const ir_strtab *strtab, ir_strtab_apply_t func);
|
||||
void ir_strtab_free(ir_strtab *strtab);
|
||||
|
||||
/* IR Context Flags */
|
||||
#define IR_FUNCTION (1<<0) /* Generate a function. */
|
||||
#define IR_FASTCALL_FUNC (1<<1) /* Generate a function with fastcall calling convention, x86 32-bit only. */
|
||||
#define IR_VARARG_FUNC (1<<2)
|
||||
#define IR_BUILTIN_FUNC (1<<3)
|
||||
#define IR_STATIC (1<<4)
|
||||
#define IR_EXTERN (1<<5)
|
||||
#define IR_CONST (1<<6)
|
||||
#define IR_PROTO_MASK 0xff
|
||||
#define IR_CALL_CONV_MASK 0x0f
|
||||
|
||||
#define IR_CONST_FUNC (1<<6)
|
||||
#define IR_PURE_FUNC (1<<7)
|
||||
#define IR_VARARG_FUNC (1<<4)
|
||||
#define IR_CONST_FUNC (1<<5)
|
||||
#define IR_PURE_FUNC (1<<6)
|
||||
|
||||
#define IR_INITIALIZED (1<<7) /* sym data flag: constant or an initialized variable */
|
||||
#define IR_CONST_STRING (1<<8) /* sym data flag: constant string */
|
||||
#define IR_CONST (1<<5)
|
||||
#define IR_INITIALIZED (1<<6) /* sym data flag: constant or an initialized variable */
|
||||
#define IR_CONST_STRING (1<<7) /* sym data flag: constant string */
|
||||
|
||||
#define IR_SKIP_PROLOGUE (1<<8) /* Don't generate function prologue. */
|
||||
#define IR_USE_FRAME_POINTER (1<<9)
|
||||
#define IR_PREALLOCATED_STACK (1<<10)
|
||||
#define IR_NO_STACK_COMBINE (1<<11)
|
||||
#define IR_START_BR_TARGET (1<<12)
|
||||
#define IR_ENTRY_BR_TARGET (1<<13)
|
||||
#define IR_GEN_ENDBR (1<<14)
|
||||
#define IR_MERGE_EMPTY_ENTRIES (1<<15)
|
||||
#define IR_FUNCTION (1<<8) /* Generate a function. */
|
||||
#define IR_STATIC (1<<9)
|
||||
#define IR_EXTERN (1<<10)
|
||||
|
||||
#define IR_OPT_INLINE (1<<16)
|
||||
#define IR_OPT_FOLDING (1<<17)
|
||||
#define IR_OPT_CFG (1<<18) /* merge BBs, by remove END->BEGIN nodes during CFG construction */
|
||||
#define IR_OPT_MEM2SSA (1<<19)
|
||||
#define IR_OPT_CODEGEN (1<<20)
|
||||
#define IR_GEN_NATIVE (1<<21)
|
||||
#define IR_GEN_CODE (1<<22) /* C or LLVM */
|
||||
#define IR_USE_FRAME_POINTER (1<<11)
|
||||
#define IR_NO_STACK_COMBINE (1<<12)
|
||||
#define IR_GEN_ENDBR (1<<13)
|
||||
#define IR_GEN_CACHE_DEMOTE (1<<14) /* Demote the generated code from closest CPU caches */
|
||||
|
||||
#define IR_GEN_CACHE_DEMOTE (1<<23) /* Demote the generated code from closest CPU caches */
|
||||
#define IR_SKIP_PROLOGUE (1<<15) /* Don't generate function prologue. */
|
||||
#define IR_START_BR_TARGET (1<<16)
|
||||
#define IR_ENTRY_BR_TARGET (1<<17)
|
||||
#define IR_MERGE_EMPTY_ENTRIES (1<<18)
|
||||
|
||||
#define IR_OPT_INLINE (1<<19)
|
||||
#define IR_OPT_FOLDING (1<<20)
|
||||
#define IR_OPT_CFG (1<<21) /* merge BBs, by remove END->BEGIN nodes during CFG construction */
|
||||
#define IR_OPT_MEM2SSA (1<<22)
|
||||
#define IR_OPT_CODEGEN (1<<23)
|
||||
#define IR_GEN_NATIVE (1<<24)
|
||||
#define IR_GEN_CODE (1<<25)
|
||||
|
||||
/* debug related */
|
||||
#ifdef IR_DEBUG
|
||||
@@ -582,6 +582,24 @@ void ir_strtab_free(ir_strtab *strtab);
|
||||
# define IR_DEBUG_BB_SCHEDULE (1U<<31)
|
||||
#endif
|
||||
|
||||
/* Calling Conventions */
|
||||
#define IR_CC_DEFAULT 0x00
|
||||
#define IR_CC_BUILTIN 0x01
|
||||
#define IR_CC_FASTCALL 0x02
|
||||
#define IR_CC_PRESERVE_NONE 0x03
|
||||
|
||||
#if defined(IR_TARGET_X64)
|
||||
# define IR_CC_X86_64_SYSV 0x08
|
||||
# define IR_CC_X86_64_MS 0x09
|
||||
#elif defined(IR_TARGET_AARCH64)
|
||||
# define IR_CC_AARCH64_SYSV 0x08
|
||||
# define IR_CC_AARCH64_DARWIN 0x09
|
||||
#endif
|
||||
|
||||
/* Deprecated constants */
|
||||
#define IR_BUILTIN_FUNC IR_CC_BUILTIN
|
||||
#define IR_FASTCALL_FUNC IR_CC_FASTCALL
|
||||
|
||||
typedef struct _ir_ctx ir_ctx;
|
||||
typedef struct _ir_use_list ir_use_list;
|
||||
typedef struct _ir_block ir_block;
|
||||
@@ -728,7 +746,7 @@ const char *ir_get_strl(const ir_ctx *ctx, ir_ref idx, size_t *len);
|
||||
#define IR_MAX_PROTO_PARAMS 255
|
||||
|
||||
typedef struct _ir_proto_t {
|
||||
uint8_t flags;
|
||||
uint8_t flags; /* first 8 bits of ir_ctx.flags */
|
||||
uint8_t ret_type;
|
||||
uint8_t params_count;
|
||||
uint8_t param_types[5];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -87,14 +87,15 @@ enum _ir_reg {
|
||||
IR_GP_REGS(IR_GP_REG_ENUM)
|
||||
IR_FP_REGS(IR_FP_REG_ENUM)
|
||||
IR_REG_NUM,
|
||||
IR_REG_ALL = IR_REG_NUM, /* special name for regset */
|
||||
IR_REG_SET_1, /* special name for regset */
|
||||
IR_REG_SET_NUM,
|
||||
};
|
||||
|
||||
#define IR_REG_GP_FIRST IR_REG_X0
|
||||
#define IR_REG_FP_FIRST IR_REG_V0
|
||||
#define IR_REG_GP_LAST (IR_REG_FP_FIRST - 1)
|
||||
#define IR_REG_FP_LAST (IR_REG_NUM - 1)
|
||||
#define IR_REG_SCRATCH (IR_REG_NUM) /* special name for regset */
|
||||
#define IR_REG_ALL (IR_REG_NUM + 1) /* special name for regset */
|
||||
|
||||
#define IR_REGSET_64BIT 1
|
||||
|
||||
@@ -125,65 +126,4 @@ enum _ir_reg {
|
||||
#define IR_REG_LR IR_REG_X30
|
||||
#define IR_REG_ZR IR_REG_X31
|
||||
|
||||
/* Calling Convention */
|
||||
#define IR_REG_INT_RET1 IR_REG_X0
|
||||
#define IR_REG_FP_RET1 IR_REG_V0
|
||||
#define IR_REG_INT_ARGS 8
|
||||
#define IR_REG_FP_ARGS 8
|
||||
#define IR_REG_INT_ARG1 IR_REG_X0
|
||||
#define IR_REG_INT_ARG2 IR_REG_X1
|
||||
#define IR_REG_INT_ARG3 IR_REG_X2
|
||||
#define IR_REG_INT_ARG4 IR_REG_X3
|
||||
#define IR_REG_INT_ARG5 IR_REG_X4
|
||||
#define IR_REG_INT_ARG6 IR_REG_X5
|
||||
#define IR_REG_INT_ARG7 IR_REG_X6
|
||||
#define IR_REG_INT_ARG8 IR_REG_X7
|
||||
#define IR_REG_FP_ARG1 IR_REG_V0
|
||||
#define IR_REG_FP_ARG2 IR_REG_V1
|
||||
#define IR_REG_FP_ARG3 IR_REG_V2
|
||||
#define IR_REG_FP_ARG4 IR_REG_V3
|
||||
#define IR_REG_FP_ARG5 IR_REG_V4
|
||||
#define IR_REG_FP_ARG6 IR_REG_V5
|
||||
#define IR_REG_FP_ARG7 IR_REG_V6
|
||||
#define IR_REG_FP_ARG8 IR_REG_V7
|
||||
#define IR_MAX_REG_ARGS 16
|
||||
#define IR_SHADOW_ARGS 0
|
||||
|
||||
# define IR_REGSET_SCRATCH \
|
||||
(IR_REGSET_INTERVAL(IR_REG_X0, IR_REG_X18) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_V0, IR_REG_V7) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_V16, IR_REG_V31))
|
||||
|
||||
# define IR_REGSET_PRESERVED \
|
||||
(IR_REGSET_INTERVAL(IR_REG_X19, IR_REG_X30) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_V8, IR_REG_V15))
|
||||
|
||||
#ifndef __APPLE__
|
||||
typedef struct _ir_va_list {
|
||||
void *stack;
|
||||
void *gr_top;
|
||||
void *vr_top;
|
||||
int32_t gr_offset;
|
||||
int32_t vr_offset;
|
||||
} ir_va_list;
|
||||
#endif
|
||||
|
||||
typedef struct _ir_tmp_reg {
|
||||
union {
|
||||
uint8_t num;
|
||||
int8_t reg;
|
||||
};
|
||||
uint8_t type;
|
||||
int8_t start;
|
||||
int8_t end;
|
||||
} ir_tmp_reg;
|
||||
|
||||
struct _ir_target_constraints {
|
||||
int8_t def_reg;
|
||||
uint8_t tmps_count;
|
||||
uint8_t hints_count;
|
||||
ir_tmp_reg tmp_regs[3];
|
||||
int8_t hints[IR_MAX_REG_ARGS + 3];
|
||||
};
|
||||
|
||||
#endif /* IR_AARCH64_H */
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
#include "ir.h"
|
||||
#include "ir_private.h"
|
||||
|
||||
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
|
||||
# include "ir_x86.h"
|
||||
#elif defined(IR_TARGET_AARCH64)
|
||||
# include "ir_aarch64.h"
|
||||
#else
|
||||
# error "Unknown IR target"
|
||||
#endif
|
||||
|
||||
void ir_dump(const ir_ctx *ctx, FILE *f)
|
||||
{
|
||||
ir_ref i, j, n, ref, *p;
|
||||
@@ -456,8 +464,8 @@ void ir_dump_live_ranges(const ir_ctx *ctx, FILE *f)
|
||||
}
|
||||
}
|
||||
#if 1
|
||||
n = ctx->vregs_count + ir_regs_number() + 2;
|
||||
for (i = ctx->vregs_count + 1; i <= n; i++) {
|
||||
n = ctx->vregs_count + 1 + IR_REG_SET_NUM;
|
||||
for (i = ctx->vregs_count + 1; i < n; i++) {
|
||||
ir_live_interval *ival = ctx->live_intervals[i];
|
||||
|
||||
if (ival) {
|
||||
|
||||
@@ -63,18 +63,7 @@ typedef struct _ir_dessa_copy {
|
||||
int32_t to; /* [0..IR_REG_NUM) - CPU reg, [IR_REG_NUM...) - virtual reg */
|
||||
} ir_dessa_copy;
|
||||
|
||||
#if IR_REG_INT_ARGS
|
||||
static const int8_t _ir_int_reg_params[IR_REG_INT_ARGS];
|
||||
#else
|
||||
static const int8_t *_ir_int_reg_params;
|
||||
#endif
|
||||
#if IR_REG_FP_ARGS
|
||||
static const int8_t _ir_fp_reg_params[IR_REG_FP_ARGS];
|
||||
#else
|
||||
static const int8_t *_ir_fp_reg_params;
|
||||
#endif
|
||||
|
||||
static const ir_proto_t *ir_call_proto(const ir_ctx *ctx, ir_insn *insn)
|
||||
const ir_proto_t *ir_call_proto(const ir_ctx *ctx, const ir_insn *insn)
|
||||
{
|
||||
if (IR_IS_CONST_REF(insn->op2)) {
|
||||
const ir_insn *func = &ctx->ir_base[insn->op2];
|
||||
@@ -90,49 +79,6 @@ static const ir_proto_t *ir_call_proto(const ir_ctx *ctx, ir_insn *insn)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef IR_HAVE_FASTCALL
|
||||
static const int8_t _ir_int_fc_reg_params[IR_REG_INT_FCARGS];
|
||||
static const int8_t *_ir_fp_fc_reg_params;
|
||||
|
||||
bool ir_is_fastcall(const ir_ctx *ctx, const ir_insn *insn)
|
||||
{
|
||||
if (sizeof(void*) == 4) {
|
||||
if (IR_IS_CONST_REF(insn->op2)) {
|
||||
const ir_insn *func = &ctx->ir_base[insn->op2];
|
||||
|
||||
if (func->op == IR_FUNC || func->op == IR_FUNC_ADDR) {
|
||||
if (func->proto) {
|
||||
const ir_proto_t *proto = (const ir_proto_t *)ir_get_str(ctx, func->proto);
|
||||
|
||||
return (proto->flags & IR_FASTCALL_FUNC) != 0;
|
||||
}
|
||||
}
|
||||
} else if (ctx->ir_base[insn->op2].op == IR_PROTO) {
|
||||
const ir_proto_t *proto = (const ir_proto_t *)ir_get_str(ctx, ctx->ir_base[insn->op2].op2);
|
||||
|
||||
return (proto->flags & IR_FASTCALL_FUNC) != 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
bool ir_is_fastcall(const ir_ctx *ctx, const ir_insn *insn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ir_is_vararg(const ir_ctx *ctx, ir_insn *insn)
|
||||
{
|
||||
const ir_proto_t *proto = ir_call_proto(ctx, insn);
|
||||
|
||||
if (proto) {
|
||||
return (proto->flags & IR_VARARG_FUNC) != 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
IR_ALWAYS_INLINE uint32_t ir_rule(const ir_ctx *ctx, ir_ref ref)
|
||||
{
|
||||
IR_ASSERT(!IR_IS_CONST_REF(ref));
|
||||
@@ -153,19 +99,7 @@ static ir_reg ir_get_param_reg(const ir_ctx *ctx, ir_ref ref)
|
||||
ir_insn *insn;
|
||||
int int_param = 0;
|
||||
int fp_param = 0;
|
||||
int int_reg_params_count = IR_REG_INT_ARGS;
|
||||
int fp_reg_params_count = IR_REG_FP_ARGS;
|
||||
const int8_t *int_reg_params = _ir_int_reg_params;
|
||||
const int8_t *fp_reg_params = _ir_fp_reg_params;
|
||||
|
||||
#ifdef IR_HAVE_FASTCALL
|
||||
if (sizeof(void*) == 4 && (ctx->flags & IR_FASTCALL_FUNC)) {
|
||||
int_reg_params_count = IR_REG_INT_FCARGS;
|
||||
fp_reg_params_count = IR_REG_FP_FCARGS;
|
||||
int_reg_params = _ir_int_fc_reg_params;
|
||||
fp_reg_params = _ir_fp_fc_reg_params;
|
||||
}
|
||||
#endif
|
||||
const ir_call_conv_dsc *cc = ir_get_call_conv_dsc(ctx->flags);
|
||||
|
||||
for (i = use_list->count, p = &ctx->use_edges[use_list->refs]; i > 0; p++, i--) {
|
||||
use = *p;
|
||||
@@ -173,70 +107,48 @@ static ir_reg ir_get_param_reg(const ir_ctx *ctx, ir_ref ref)
|
||||
if (insn->op == IR_PARAM) {
|
||||
if (IR_IS_TYPE_INT(insn->type)) {
|
||||
if (use == ref) {
|
||||
#if defined(IR_TARGET_X64) || defined(IR_TARGET_X86)
|
||||
if (ctx->value_params && ctx->value_params[insn->op3 - 1].align) {
|
||||
if (ctx->value_params && ctx->value_params[insn->op3 - 1].align && cc->pass_struct_by_val) {
|
||||
/* struct passed by value on stack */
|
||||
return IR_REG_NONE;
|
||||
} else
|
||||
#endif
|
||||
if (int_param < int_reg_params_count) {
|
||||
return int_reg_params[int_param];
|
||||
} else if (int_param < cc->int_param_regs_count) {
|
||||
return cc->int_param_regs[int_param];
|
||||
} else {
|
||||
return IR_REG_NONE;
|
||||
}
|
||||
#if defined(IR_TARGET_X64) || defined(IR_TARGET_X86)
|
||||
} else {
|
||||
if (ctx->value_params && ctx->value_params[insn->op3 - 1].align) {
|
||||
/* struct passed by value on stack */
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
} else if (ctx->value_params && ctx->value_params[insn->op3 - 1].align && cc->pass_struct_by_val) {
|
||||
/* struct passed by value on stack */
|
||||
continue;
|
||||
}
|
||||
int_param++;
|
||||
#ifdef _WIN64
|
||||
/* WIN64 calling convention use common couter for int and fp registers */
|
||||
fp_param++;
|
||||
#endif
|
||||
if (cc->shadow_param_regs) {
|
||||
fp_param++;
|
||||
}
|
||||
} else {
|
||||
IR_ASSERT(IR_IS_TYPE_FP(insn->type));
|
||||
if (use == ref) {
|
||||
if (fp_param < fp_reg_params_count) {
|
||||
return fp_reg_params[fp_param];
|
||||
if (fp_param < cc->fp_param_regs_count) {
|
||||
return cc->fp_param_regs[fp_param];
|
||||
} else {
|
||||
return IR_REG_NONE;
|
||||
}
|
||||
}
|
||||
fp_param++;
|
||||
#ifdef _WIN64
|
||||
/* WIN64 calling convention use common couter for int and fp registers */
|
||||
int_param++;
|
||||
#endif
|
||||
if (cc->shadow_param_regs) {
|
||||
int_param++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return IR_REG_NONE;
|
||||
}
|
||||
|
||||
static int ir_get_args_regs(const ir_ctx *ctx, const ir_insn *insn, int8_t *regs)
|
||||
static int ir_get_args_regs(const ir_ctx *ctx, const ir_insn *insn, const ir_call_conv_dsc *cc, int8_t *regs)
|
||||
{
|
||||
int j, n;
|
||||
ir_type type;
|
||||
int int_param = 0;
|
||||
int fp_param = 0;
|
||||
int count = 0;
|
||||
int int_reg_params_count = IR_REG_INT_ARGS;
|
||||
int fp_reg_params_count = IR_REG_FP_ARGS;
|
||||
const int8_t *int_reg_params = _ir_int_reg_params;
|
||||
const int8_t *fp_reg_params = _ir_fp_reg_params;
|
||||
|
||||
#ifdef IR_HAVE_FASTCALL
|
||||
if (sizeof(void*) == 4 && ir_is_fastcall(ctx, insn)) {
|
||||
int_reg_params_count = IR_REG_INT_FCARGS;
|
||||
fp_reg_params_count = IR_REG_FP_FCARGS;
|
||||
int_reg_params = _ir_int_fc_reg_params;
|
||||
fp_reg_params = _ir_fp_fc_reg_params;
|
||||
}
|
||||
#endif
|
||||
|
||||
n = insn->inputs_count;
|
||||
n = IR_MIN(n, IR_MAX_REG_ARGS + 2);
|
||||
@@ -244,27 +156,25 @@ static int ir_get_args_regs(const ir_ctx *ctx, const ir_insn *insn, int8_t *regs
|
||||
ir_insn *arg = &ctx->ir_base[ir_insn_op(insn, j)];
|
||||
type = arg->type;
|
||||
if (IR_IS_TYPE_INT(type)) {
|
||||
if (int_param < int_reg_params_count && arg->op != IR_ARGVAL) {
|
||||
regs[j] = int_reg_params[int_param];
|
||||
if (int_param < cc->int_param_regs_count && arg->op != IR_ARGVAL) {
|
||||
regs[j] = cc->int_param_regs[int_param];
|
||||
count = j + 1;
|
||||
int_param++;
|
||||
#ifdef _WIN64
|
||||
/* WIN64 calling convention use common couter for int and fp registers */
|
||||
fp_param++;
|
||||
#endif
|
||||
if (cc->shadow_param_regs) {
|
||||
fp_param++;
|
||||
}
|
||||
} else {
|
||||
regs[j] = IR_REG_NONE;
|
||||
}
|
||||
} else {
|
||||
IR_ASSERT(IR_IS_TYPE_FP(type));
|
||||
if (fp_param < fp_reg_params_count) {
|
||||
regs[j] = fp_reg_params[fp_param];
|
||||
if (fp_param < cc->fp_param_regs_count) {
|
||||
regs[j] = cc->fp_param_regs[fp_param];
|
||||
count = j + 1;
|
||||
fp_param++;
|
||||
#ifdef _WIN64
|
||||
/* WIN64 calling convention use common couter for int and fp registers */
|
||||
int_param++;
|
||||
#endif
|
||||
if (cc->shadow_param_regs) {
|
||||
int_param++;
|
||||
}
|
||||
} else {
|
||||
regs[j] = IR_REG_NONE;
|
||||
}
|
||||
@@ -419,7 +329,6 @@ static void ir_emit_dessa_moves(ir_ctx *ctx, int b, ir_block *bb);
|
||||
|
||||
typedef struct _ir_common_backend_data {
|
||||
ir_reg_alloc_data ra_data;
|
||||
uint32_t dessa_from_block;
|
||||
dasm_State *dasm_state;
|
||||
ir_bitset emit_constants;
|
||||
} ir_common_backend_data;
|
||||
@@ -1071,3 +980,32 @@ int32_t ir_get_spill_slot_offset(ir_ctx *ctx, ir_ref ref)
|
||||
IR_ASSERT(offset != -1);
|
||||
return IR_SPILL_POS_TO_OFFSET(offset);
|
||||
}
|
||||
|
||||
const ir_call_conv_dsc *ir_get_call_conv_dsc(uint32_t flags)
|
||||
{
|
||||
#ifdef IR_TARGET_X86
|
||||
if ((flags & IR_CALL_CONV_MASK) == IR_CC_FASTCALL) {
|
||||
return &ir_call_conv_x86_fastcall;
|
||||
}
|
||||
#elif defined(IR_TARGET_X64)
|
||||
switch (flags & IR_CALL_CONV_MASK) {
|
||||
case IR_CC_DEFAULT: return &ir_call_conv_default;
|
||||
case IR_CC_FASTCALL: return &ir_call_conv_default;
|
||||
case IR_CC_PRESERVE_NONE: return &ir_call_conv_x86_64_preserve_none;
|
||||
case IR_CC_X86_64_SYSV: return &ir_call_conv_x86_64_sysv;
|
||||
case IR_CC_X86_64_MS: return &ir_call_conv_x86_64_ms;
|
||||
default: break;
|
||||
}
|
||||
#elif defined(IR_TARGET_AARCH64)
|
||||
switch (flags & IR_CALL_CONV_MASK) {
|
||||
case IR_CC_DEFAULT: return &ir_call_conv_default;
|
||||
case IR_CC_FASTCALL: return &ir_call_conv_default;
|
||||
case IR_CC_PRESERVE_NONE: return &ir_call_conv_aarch64_preserve_none;
|
||||
case IR_CC_AARCH64_SYSV: return &ir_call_conv_aarch64_sysv;
|
||||
case IR_CC_AARCH64_DARWIN: return &ir_call_conv_aarch64_darwin;
|
||||
default: break;
|
||||
}
|
||||
#endif
|
||||
IR_ASSERT((flags & IR_CALL_CONV_MASK) == IR_CC_DEFAULT || (flags & IR_CALL_CONV_MASK) == IR_CC_BUILTIN);
|
||||
return &ir_call_conv_default;
|
||||
}
|
||||
|
||||
@@ -361,20 +361,20 @@ static bool ir_split_partially_dead_node(ir_ctx *ctx, ir_ref ref, uint32_t b)
|
||||
while (ir_sparse_set_in(&data->totally_useful, ctx->cfg_blocks[j].idom)) {
|
||||
j = ctx->cfg_blocks[j].idom;
|
||||
}
|
||||
clone = ir_hashtab_find(&hash, j);
|
||||
if (clone == IR_INVALID_VAL) {
|
||||
clone = clones_count++;
|
||||
ir_hashtab_add(&hash, j, clone);
|
||||
clones[clone].block = j;
|
||||
clones[clone].use_count = 0;
|
||||
clones[clone].use = -1;
|
||||
}
|
||||
uses[uses_count].ref = use;
|
||||
uses[uses_count].block = i;
|
||||
uses[uses_count].next = clones[clone].use;
|
||||
clones[clone].use_count++;
|
||||
clones[clone].use = uses_count++;
|
||||
}
|
||||
clone = ir_hashtab_find(&hash, j);
|
||||
if (clone == IR_INVALID_VAL) {
|
||||
clone = clones_count++;
|
||||
ir_hashtab_add(&hash, j, clone);
|
||||
clones[clone].block = j;
|
||||
clones[clone].use_count = 0;
|
||||
clones[clone].use = -1;
|
||||
}
|
||||
uses[uses_count].ref = use;
|
||||
uses[uses_count].block = i;
|
||||
uses[uses_count].next = clones[clone].use;
|
||||
clones[clone].use_count++;
|
||||
clones[clone].use = uses_count++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +413,8 @@ static bool ir_split_partially_dead_node(ir_ctx *ctx, ir_ref ref, uint32_t b)
|
||||
n = ctx->use_lists[ref].refs;
|
||||
for (i = 0; i < clones_count; i++) {
|
||||
clone = clones[i].ref;
|
||||
if (clones[i].use_count == 1
|
||||
if (clones[i].block
|
||||
&& clones[i].use_count == 1
|
||||
&& ctx->cfg_blocks[clones[i].block].loop_depth >= ctx->cfg_blocks[uses[clones[i].use].block].loop_depth) {
|
||||
/* TOTALLY_USEFUL block may be a head of a diamond above the real usage.
|
||||
* Sink it down to the real usage block.
|
||||
|
||||
@@ -1015,6 +1015,8 @@ IR_ALWAYS_INLINE uint32_t ir_insn_len(const ir_insn *insn)
|
||||
#define IR_HAS_FP_RET_SLOT (1<<10)
|
||||
#define IR_16B_FRAME_ALIGNMENT (1<<11)
|
||||
#define IR_HAS_BLOCK_ADDR (1<<12)
|
||||
#define IR_PREALLOCATED_STACK (1<<13)
|
||||
|
||||
|
||||
/* Temporary: MEM2SSA -> SCCP */
|
||||
#define IR_MEM2SSA_VARS (1<<25)
|
||||
@@ -1275,9 +1277,9 @@ struct _ir_live_interval {
|
||||
ir_live_interval *list_next; /* linked list of active, inactive or unhandled intervals */
|
||||
};
|
||||
|
||||
typedef int (*emit_copy_t)(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to);
|
||||
typedef int (*emit_copy_t)(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to, void *data);
|
||||
|
||||
int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy);
|
||||
int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy, void *data);
|
||||
|
||||
#if defined(IR_REGSET_64BIT)
|
||||
|
||||
@@ -1363,16 +1365,44 @@ IR_ALWAYS_INLINE ir_reg ir_regset_pop_first(ir_regset *set)
|
||||
|
||||
#endif /* defined(IR_REGSET_64BIT) */
|
||||
|
||||
/*** Calling Conventions ***/
|
||||
#if defined(IR_REGSET_64BIT)
|
||||
struct _ir_call_conv_dsc {
|
||||
bool cleanup_stack_by_callee: 1; /* use "retn $size" to return */
|
||||
bool pass_struct_by_val: 1; /* pass aggreagate by value, otherwise their copies are passed by ref */
|
||||
bool sysv_varargs: 1; /* Use SysV varargs ABI */
|
||||
bool shadow_param_regs: 1; /* registers for INT and FP parametrs shadow each other */
|
||||
/* (WIN64: 1-st arg is passed in %rcx/%xmm0, 2-nd in %rdx/%xmm1) */
|
||||
uint8_t shadow_store_size; /* reserved stack space to keep arguemnts passed in registers (WIN64) */
|
||||
uint8_t int_param_regs_count; /* number of registers for INT parameters */
|
||||
uint8_t fp_param_regs_count; /* number of registers for FP parameters */
|
||||
int8_t int_ret_reg; /* register to return INT value */
|
||||
int8_t fp_ret_reg; /* register to return FP value */
|
||||
int8_t fp_varargs_reg; /* register to pass number of fp register arguments into vararg func */
|
||||
int8_t scratch_reg; /* pseudo register to reffer srcatch regset (clobbered by call) */
|
||||
const int8_t *int_param_regs; /* registers for INT parameters */
|
||||
const int8_t *fp_param_regs; /* registers for FP parameters */
|
||||
ir_regset preserved_regs; /* preserved or callee-saved registers */
|
||||
};
|
||||
|
||||
extern const ir_regset ir_scratch_regset[];
|
||||
#endif
|
||||
|
||||
typedef struct _ir_call_conv_dsc ir_call_conv_dsc;
|
||||
|
||||
const ir_call_conv_dsc *ir_get_call_conv_dsc(uint32_t flags);
|
||||
|
||||
/*** IR Register Allocation ***/
|
||||
/* Flags for ctx->regs[][] (low bits are used for register number itself) */
|
||||
typedef struct _ir_reg_alloc_data {
|
||||
const ir_call_conv_dsc *cc;
|
||||
int32_t unused_slot_4;
|
||||
int32_t unused_slot_2;
|
||||
int32_t unused_slot_1;
|
||||
ir_live_interval **handled;
|
||||
} ir_reg_alloc_data;
|
||||
|
||||
int32_t ir_allocate_spill_slot(ir_ctx *ctx, ir_type type, ir_reg_alloc_data *data);
|
||||
int32_t ir_allocate_spill_slot(ir_ctx *ctx, ir_type type);
|
||||
|
||||
IR_ALWAYS_INLINE void ir_set_alocated_reg(ir_ctx *ctx, ir_ref ref, int op_num, int8_t reg)
|
||||
{
|
||||
@@ -1406,9 +1436,27 @@ IR_ALWAYS_INLINE int8_t ir_get_alocated_reg(const ir_ctx *ctx, ir_ref ref, int o
|
||||
|
||||
#define IR_RULE_MASK 0xff
|
||||
|
||||
#define IR_MAX_REG_ARGS 64
|
||||
|
||||
extern const char *ir_rule_name[];
|
||||
|
||||
typedef struct _ir_target_constraints ir_target_constraints;
|
||||
typedef struct _ir_tmp_reg {
|
||||
union {
|
||||
uint8_t num;
|
||||
int8_t reg;
|
||||
};
|
||||
uint8_t type;
|
||||
int8_t start;
|
||||
int8_t end;
|
||||
} ir_tmp_reg;
|
||||
|
||||
typedef struct {
|
||||
int8_t def_reg;
|
||||
uint8_t tmps_count;
|
||||
uint8_t hints_count;
|
||||
ir_tmp_reg tmp_regs[3];
|
||||
int8_t hints[IR_MAX_REG_ARGS + 3];
|
||||
} ir_target_constraints;
|
||||
|
||||
#define IR_TMP_REG(_num, _type, _start, _end) \
|
||||
(ir_tmp_reg){.num=(_num), .type=(_type), .start=(_start), .end=(_end)}
|
||||
@@ -1421,8 +1469,8 @@ void ir_fix_stack_frame(ir_ctx *ctx);
|
||||
|
||||
/* Utility */
|
||||
ir_type ir_get_return_type(ir_ctx *ctx);
|
||||
bool ir_is_fastcall(const ir_ctx *ctx, const ir_insn *insn);
|
||||
bool ir_is_vararg(const ir_ctx *ctx, ir_insn *insn);
|
||||
const ir_proto_t *ir_call_proto(const ir_ctx *ctx, const ir_insn *insn);
|
||||
void ir_print_call_conv(uint32_t flags, FILE *f);
|
||||
|
||||
//#define IR_BITSET_LIVENESS
|
||||
|
||||
|
||||
@@ -610,8 +610,8 @@ int ir_compute_live_ranges(ir_ctx *ctx)
|
||||
len = ir_bitset_len(ctx->vregs_count + 1);
|
||||
bb_live = ir_mem_malloc((ctx->cfg_blocks_count + 1) * len * sizeof(ir_bitset_base_t));
|
||||
|
||||
/* vregs + tmp + fixed + SRATCH + ALL */
|
||||
ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_NUM + 2, sizeof(ir_live_interval*));
|
||||
/* vregs + tmp + fixed + ALL + SCRATCH_N */
|
||||
ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_SET_NUM, sizeof(ir_live_interval*));
|
||||
|
||||
#ifdef IR_DEBUG
|
||||
visited = ir_bitset_malloc(ctx->cfg_blocks_count + 1);
|
||||
@@ -1265,8 +1265,8 @@ int ir_compute_live_ranges(ir_ctx *ctx)
|
||||
/* Compute Live Ranges */
|
||||
ctx->flags2 &= ~IR_LR_HAVE_DESSA_MOVES;
|
||||
|
||||
/* vregs + tmp + fixed + SRATCH + ALL */
|
||||
ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_NUM + 2, sizeof(ir_live_interval*));
|
||||
/* vregs + tmp + fixed + ALL + SCRATCH_N */
|
||||
ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_SET_NUM, sizeof(ir_live_interval*));
|
||||
|
||||
if (!ctx->arena) {
|
||||
ctx->arena = ir_arena_create(16 * 1024);
|
||||
@@ -2037,8 +2037,8 @@ int ir_coalesce(ir_ctx *ctx)
|
||||
n--;
|
||||
if (n != ctx->vregs_count) {
|
||||
j = ctx->vregs_count - n;
|
||||
/* vregs + tmp + fixed + SRATCH + ALL */
|
||||
for (i = n + 1; i <= n + IR_REG_NUM + 2; i++) {
|
||||
/* vregs + tmp + fixed + ALL + SCRATCH_N */
|
||||
for (i = n + 1; i <= n + IR_REG_SET_NUM; i++) {
|
||||
ctx->live_intervals[i] = ctx->live_intervals[i + j];
|
||||
if (ctx->live_intervals[i]) {
|
||||
ctx->live_intervals[i]->vreg = i;
|
||||
@@ -2105,7 +2105,7 @@ int ir_compute_dessa_moves(ir_ctx *ctx)
|
||||
* 2009 International Symposium on Code Generation and Optimization, Seattle, WA, USA, 2009,
|
||||
* pp. 114-125, doi: 10.1109/CGO.2009.19.
|
||||
*/
|
||||
int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy)
|
||||
int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy, void *data)
|
||||
{
|
||||
uint32_t succ, k, n = 0;
|
||||
ir_block *bb, *succ_bb;
|
||||
@@ -2180,7 +2180,7 @@ int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy)
|
||||
while ((b = ir_bitset_pop_first(ready, len)) >= 0) {
|
||||
a = pred[b];
|
||||
c = loc[a];
|
||||
emit_copy(ctx, ctx->ir_base[dst[b]].type, src[c], dst[b]);
|
||||
emit_copy(ctx, ctx->ir_base[dst[b]].type, src[c], dst[b], data);
|
||||
ir_bitset_excl(todo, b);
|
||||
loc[a] = b;
|
||||
src[b] = dst[b];
|
||||
@@ -2193,7 +2193,7 @@ int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy)
|
||||
break;
|
||||
}
|
||||
IR_ASSERT(b != loc[pred[b]]);
|
||||
emit_copy(ctx, ctx->ir_base[src[b]].type, src[b], 0);
|
||||
emit_copy(ctx, ctx->ir_base[src[b]].type, src[b], 0, data);
|
||||
loc[b] = 0;
|
||||
ir_bitset_incl(ready, b);
|
||||
}
|
||||
@@ -2211,7 +2211,7 @@ int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy)
|
||||
if (insn->op == IR_PHI) {
|
||||
input = ir_insn_op(insn, k);
|
||||
if (IR_IS_CONST_REF(input) || !ctx->vregs[input]) {
|
||||
emit_copy(ctx, insn->type, input, ref);
|
||||
emit_copy(ctx, insn->type, input, ref, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2501,8 +2501,9 @@ static ir_live_interval *ir_split_interval_at(ir_ctx *ctx, ir_live_interval *iva
|
||||
return child;
|
||||
}
|
||||
|
||||
static int32_t ir_allocate_small_spill_slot(ir_ctx *ctx, size_t size, ir_reg_alloc_data *data)
|
||||
static int32_t ir_allocate_small_spill_slot(ir_ctx *ctx, size_t size)
|
||||
{
|
||||
ir_reg_alloc_data *data = ctx->data;
|
||||
int32_t ret;
|
||||
|
||||
IR_ASSERT(size == 0 || size == 1 || size == 2 || size == 4 || size == 8);
|
||||
@@ -2601,12 +2602,12 @@ static int32_t ir_allocate_small_spill_slot(ir_ctx *ctx, size_t size, ir_reg_all
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t ir_allocate_spill_slot(ir_ctx *ctx, ir_type type, ir_reg_alloc_data *data)
|
||||
int32_t ir_allocate_spill_slot(ir_ctx *ctx, ir_type type)
|
||||
{
|
||||
return ir_allocate_small_spill_slot(ctx, ir_type_size[type], data);
|
||||
return ir_allocate_small_spill_slot(ctx, ir_type_size[type]);
|
||||
}
|
||||
|
||||
static int32_t ir_allocate_big_spill_slot(ir_ctx *ctx, int32_t size, ir_reg_alloc_data *data)
|
||||
static int32_t ir_allocate_big_spill_slot(ir_ctx *ctx, int32_t size)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
@@ -2616,7 +2617,7 @@ static int32_t ir_allocate_big_spill_slot(ir_ctx *ctx, int32_t size, ir_reg_allo
|
||||
} else if (size > 4 && size < 8) {
|
||||
size = 8;
|
||||
}
|
||||
return ir_allocate_small_spill_slot(ctx, size, data);
|
||||
return ir_allocate_small_spill_slot(ctx, size);
|
||||
}
|
||||
|
||||
/* Align stack allocated data to 16 byte */
|
||||
@@ -2836,13 +2837,8 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l
|
||||
/* freeUntilPos[it.reg] = 0 */
|
||||
reg = other->reg;
|
||||
IR_ASSERT(reg >= 0);
|
||||
if (reg >= IR_REG_SCRATCH) {
|
||||
if (reg == IR_REG_SCRATCH) {
|
||||
available = IR_REGSET_DIFFERENCE(available, IR_REGSET_SCRATCH);
|
||||
} else {
|
||||
IR_ASSERT(reg == IR_REG_ALL);
|
||||
available = IR_REGSET_EMPTY;
|
||||
}
|
||||
if (reg >= IR_REG_NUM) {
|
||||
available = IR_REGSET_DIFFERENCE(available, ir_scratch_regset[reg - IR_REG_NUM]);
|
||||
} else {
|
||||
IR_REGSET_EXCL(available, reg);
|
||||
}
|
||||
@@ -2864,15 +2860,8 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l
|
||||
if (next) {
|
||||
reg = other->reg;
|
||||
IR_ASSERT(reg >= 0);
|
||||
if (reg >= IR_REG_SCRATCH) {
|
||||
ir_regset regset;
|
||||
|
||||
if (reg == IR_REG_SCRATCH) {
|
||||
regset = IR_REGSET_INTERSECTION(available, IR_REGSET_SCRATCH);
|
||||
} else {
|
||||
IR_ASSERT(reg == IR_REG_ALL);
|
||||
regset = available;
|
||||
}
|
||||
if (reg >= IR_REG_NUM) {
|
||||
ir_regset regset = IR_REGSET_INTERSECTION(available, ir_scratch_regset[reg - IR_REG_NUM]);
|
||||
overlapped = IR_REGSET_UNION(overlapped, regset);
|
||||
IR_REGSET_FOREACH(regset, reg) {
|
||||
if (next < freeUntilPos[reg]) {
|
||||
@@ -2922,7 +2911,8 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l
|
||||
}
|
||||
|
||||
/* prefer caller-saved registers to avoid save/restore in prologue/epilogue */
|
||||
scratch = IR_REGSET_INTERSECTION(available, IR_REGSET_SCRATCH);
|
||||
scratch = IR_REGSET_INTERSECTION(available,
|
||||
ir_scratch_regset[((ir_reg_alloc_data*)(ctx->data))->cc->scratch_reg - IR_REG_NUM]);
|
||||
if (scratch != IR_REGSET_EMPTY) {
|
||||
/* prefer registers that don't conflict with the hints for the following unhandled intervals */
|
||||
if (1) {
|
||||
@@ -2970,8 +2960,8 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l
|
||||
pos = freeUntilPos[i];
|
||||
reg = i;
|
||||
} else if (freeUntilPos[i] == pos
|
||||
&& !IR_REGSET_IN(IR_REGSET_SCRATCH, reg)
|
||||
&& IR_REGSET_IN(IR_REGSET_SCRATCH, i)) {
|
||||
&& !IR_REGSET_IN(ir_scratch_regset[((ir_reg_alloc_data*)(ctx->data))->cc->scratch_reg - IR_REG_NUM], reg)
|
||||
&& IR_REGSET_IN(ir_scratch_regset[((ir_reg_alloc_data*)(ctx->data))->cc->scratch_reg - IR_REG_NUM], i)) {
|
||||
/* prefer caller-saved registers to avoid save/restore in prologue/epilogue */
|
||||
pos = freeUntilPos[i];
|
||||
reg = i;
|
||||
@@ -3077,15 +3067,8 @@ static ir_reg ir_allocate_blocked_reg(ir_ctx *ctx, ir_live_interval *ival, ir_li
|
||||
/* nextUsePos[it.reg] = next use of it after start of current */
|
||||
reg = other->reg;
|
||||
IR_ASSERT(reg >= 0);
|
||||
if (reg >= IR_REG_SCRATCH) {
|
||||
ir_regset regset;
|
||||
|
||||
if (reg == IR_REG_SCRATCH) {
|
||||
regset = IR_REGSET_INTERSECTION(available, IR_REGSET_SCRATCH);
|
||||
} else {
|
||||
IR_ASSERT(reg == IR_REG_ALL);
|
||||
regset = available;
|
||||
}
|
||||
if (reg >= IR_REG_NUM) {
|
||||
ir_regset regset = IR_REGSET_INTERSECTION(available, ir_scratch_regset[reg - IR_REG_NUM]);
|
||||
IR_REGSET_FOREACH(regset, reg) {
|
||||
blockPos[reg] = nextUsePos[reg] = 0;
|
||||
} IR_REGSET_FOREACH_END();
|
||||
@@ -3109,18 +3092,11 @@ static ir_reg ir_allocate_blocked_reg(ir_ctx *ctx, ir_live_interval *ival, ir_li
|
||||
/* freeUntilPos[it.reg] = next intersection of it with current */
|
||||
reg = other->reg;
|
||||
IR_ASSERT(reg >= 0);
|
||||
if (reg >= IR_REG_SCRATCH) {
|
||||
if (reg >= IR_REG_NUM) {
|
||||
ir_live_pos overlap = ir_ivals_overlap(&ival->range, other->current_range);
|
||||
|
||||
if (overlap) {
|
||||
ir_regset regset;
|
||||
|
||||
if (reg == IR_REG_SCRATCH) {
|
||||
regset = IR_REGSET_INTERSECTION(available, IR_REGSET_SCRATCH);
|
||||
} else {
|
||||
IR_ASSERT(reg == IR_REG_ALL);
|
||||
regset = available;
|
||||
}
|
||||
ir_regset regset = IR_REGSET_INTERSECTION(available, ir_scratch_regset[reg - IR_REG_NUM]);
|
||||
IR_REGSET_FOREACH(regset, reg) {
|
||||
if (overlap < nextUsePos[reg]) {
|
||||
nextUsePos[reg] = overlap;
|
||||
@@ -3325,9 +3301,9 @@ select_register:
|
||||
return reg;
|
||||
}
|
||||
|
||||
static int ir_fix_dessa_tmps(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to)
|
||||
static int ir_fix_dessa_tmps(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to, void *data)
|
||||
{
|
||||
ir_block *bb = ctx->data;
|
||||
ir_block *bb = data;
|
||||
ir_tmp_reg tmp_reg;
|
||||
|
||||
if (to == 0) {
|
||||
@@ -3365,7 +3341,7 @@ static int ir_fix_dessa_tmps(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool ir_ival_spill_for_fuse_load(ir_ctx *ctx, ir_live_interval *ival, ir_reg_alloc_data *data)
|
||||
static bool ir_ival_spill_for_fuse_load(ir_ctx *ctx, ir_live_interval *ival)
|
||||
{
|
||||
ir_use_pos *use_pos = ival->use_pos;
|
||||
|
||||
@@ -3417,7 +3393,7 @@ static void ir_assign_bound_spill_slots(ir_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static int ir_linear_scan(ir_ctx *ctx)
|
||||
static int ir_linear_scan(ir_ctx *ctx, ir_ref vars)
|
||||
{
|
||||
uint32_t b;
|
||||
ir_block *bb;
|
||||
@@ -3428,8 +3404,6 @@ static int ir_linear_scan(ir_ctx *ctx)
|
||||
int j;
|
||||
ir_live_pos position;
|
||||
ir_reg reg;
|
||||
ir_reg_alloc_data data;
|
||||
ir_ref vars = ctx->vars;
|
||||
|
||||
if (!ctx->live_intervals) {
|
||||
return 0;
|
||||
@@ -3440,19 +3414,11 @@ static int ir_linear_scan(ir_ctx *ctx)
|
||||
for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||
if (bb->flags & IR_BB_DESSA_MOVES) {
|
||||
ctx->data = bb;
|
||||
ir_gen_dessa_moves(ctx, b, ir_fix_dessa_tmps);
|
||||
ir_gen_dessa_moves(ctx, b, ir_fix_dessa_tmps, bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx->data = &data;
|
||||
ctx->stack_frame_size = 0;
|
||||
data.unused_slot_4 = 0;
|
||||
data.unused_slot_2 = 0;
|
||||
data.unused_slot_1 = 0;
|
||||
data.handled = NULL;
|
||||
|
||||
while (vars) {
|
||||
ir_ref var = vars;
|
||||
ir_insn *insn = &ctx->ir_base[var];
|
||||
@@ -3461,7 +3427,7 @@ static int ir_linear_scan(ir_ctx *ctx)
|
||||
vars = insn->op3; /* list next */
|
||||
|
||||
if (insn->op == IR_VAR) {
|
||||
ir_ref slot = ir_allocate_spill_slot(ctx, insn->type, &data);;
|
||||
ir_ref slot = ir_allocate_spill_slot(ctx, insn->type);
|
||||
ir_use_list *use_list;
|
||||
ir_ref n, *p;
|
||||
|
||||
@@ -3484,7 +3450,7 @@ static int ir_linear_scan(ir_ctx *ctx)
|
||||
IR_ASSERT(IR_IS_TYPE_UNSIGNED(val->type) || val->val.i64 >= 0);
|
||||
IR_ASSERT(val->val.i64 < 0x7fffffff);
|
||||
|
||||
insn->op3 = ir_allocate_big_spill_slot(ctx, val->val.i32, &data);
|
||||
insn->op3 = ir_allocate_big_spill_slot(ctx, val->val.i32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3492,7 +3458,7 @@ static int ir_linear_scan(ir_ctx *ctx)
|
||||
ival = ctx->live_intervals[j];
|
||||
if (ival) {
|
||||
if (!(ival->flags & IR_LIVE_INTERVAL_MEM_PARAM)
|
||||
|| !ir_ival_spill_for_fuse_load(ctx, ival, &data)) {
|
||||
|| !ir_ival_spill_for_fuse_load(ctx, ival)) {
|
||||
ir_add_to_unhandled(&unhandled, ival);
|
||||
}
|
||||
}
|
||||
@@ -3503,8 +3469,8 @@ static int ir_linear_scan(ir_ctx *ctx)
|
||||
ir_merge_to_unhandled(&unhandled, ival);
|
||||
}
|
||||
|
||||
/* vregs + tmp + fixed + SRATCH + ALL */
|
||||
for (j = ctx->vregs_count + 1; j <= ctx->vregs_count + IR_REG_NUM + 2; j++) {
|
||||
/* vregs + tmp + fixed + ALL + SCRATCH_N */
|
||||
for (j = ctx->vregs_count + 1; j <= ctx->vregs_count + IR_REG_SET_NUM; j++) {
|
||||
ival = ctx->live_intervals[j];
|
||||
if (ival) {
|
||||
ival->current_range = &ival->range;
|
||||
@@ -3663,7 +3629,7 @@ static int ir_linear_scan(ir_ctx *ctx)
|
||||
ir_live_interval *handled[9] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
|
||||
ir_live_interval *old;
|
||||
|
||||
data.handled = handled;
|
||||
((ir_reg_alloc_data*)(ctx->data))->handled = handled;
|
||||
active = NULL;
|
||||
while (unhandled) {
|
||||
ival = unhandled;
|
||||
@@ -3701,7 +3667,7 @@ static int ir_linear_scan(ir_ctx *ctx)
|
||||
other = prev ? prev->list_next : active;
|
||||
}
|
||||
|
||||
ival->stack_spill_pos = ir_allocate_spill_slot(ctx, ival->type, &data);
|
||||
ival->stack_spill_pos = ir_allocate_spill_slot(ctx, ival->type);
|
||||
if (unhandled && ival->end > unhandled->range.start) {
|
||||
ival->list_next = active;
|
||||
active = ival;
|
||||
@@ -3721,15 +3687,16 @@ static int ir_linear_scan(ir_ctx *ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
data.handled = NULL;
|
||||
((ir_reg_alloc_data*)(ctx->data))->handled = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IR_TARGET_X86
|
||||
if (ctx->flags2 & IR_HAS_FP_RET_SLOT) {
|
||||
ctx->ret_slot = ir_allocate_spill_slot(ctx, IR_DOUBLE, &data);
|
||||
} else if (ctx->ret_type == IR_FLOAT || ctx->ret_type == IR_DOUBLE) {
|
||||
ctx->ret_slot = ir_allocate_spill_slot(ctx, ctx->ret_type, &data);
|
||||
ctx->ret_slot = ir_allocate_spill_slot(ctx, IR_DOUBLE);
|
||||
} else if ((ctx->ret_type == IR_FLOAT || ctx->ret_type == IR_DOUBLE)
|
||||
&& ((ir_reg_alloc_data*)(ctx->data))->cc->fp_ret_reg == IR_REG_NONE) {
|
||||
ctx->ret_slot = ir_allocate_spill_slot(ctx, ctx->ret_type);
|
||||
} else {
|
||||
ctx->ret_slot = -1;
|
||||
}
|
||||
@@ -4033,17 +4000,18 @@ static void assign_regs(ir_ctx *ctx)
|
||||
} while (ival);
|
||||
}
|
||||
|
||||
const ir_call_conv_dsc *cc = ((ir_reg_alloc_data*)(ctx->data))->cc;
|
||||
if (ctx->fixed_stack_frame_size != -1) {
|
||||
ctx->used_preserved_regs = (ir_regset)ctx->fixed_save_regset;
|
||||
if (IR_REGSET_DIFFERENCE(IR_REGSET_INTERSECTION(used_regs, IR_REGSET_PRESERVED),
|
||||
if (IR_REGSET_DIFFERENCE(IR_REGSET_INTERSECTION(used_regs, cc->preserved_regs),
|
||||
ctx->used_preserved_regs)) {
|
||||
// TODO: Preserved reg and fixed frame conflict ???
|
||||
// IR_ASSERT(0 && "Preserved reg and fixed frame conflict");
|
||||
}
|
||||
} else {
|
||||
ctx->used_preserved_regs = IR_REGSET_UNION((ir_regset)ctx->fixed_save_regset,
|
||||
IR_REGSET_DIFFERENCE(IR_REGSET_INTERSECTION(used_regs, IR_REGSET_PRESERVED),
|
||||
(ctx->flags & IR_FUNCTION) ? (ir_regset)ctx->fixed_regset : IR_REGSET_PRESERVED));
|
||||
IR_REGSET_DIFFERENCE(IR_REGSET_INTERSECTION(used_regs, cc->preserved_regs),
|
||||
(ctx->flags & IR_FUNCTION) ? (ir_regset)ctx->fixed_regset : cc->preserved_regs));
|
||||
}
|
||||
|
||||
ir_fix_stack_frame(ctx);
|
||||
@@ -4051,9 +4019,24 @@ static void assign_regs(ir_ctx *ctx)
|
||||
|
||||
int ir_reg_alloc(ir_ctx *ctx)
|
||||
{
|
||||
if (ir_linear_scan(ctx)) {
|
||||
ir_reg_alloc_data data;
|
||||
ir_ref vars = ctx->vars;
|
||||
|
||||
data.cc = ir_get_call_conv_dsc(ctx->flags);
|
||||
data.unused_slot_4 = 0;
|
||||
data.unused_slot_2 = 0;
|
||||
data.unused_slot_1 = 0;
|
||||
data.handled = NULL;
|
||||
|
||||
ctx->data = &data;
|
||||
ctx->stack_frame_size = 0;
|
||||
|
||||
if (ir_linear_scan(ctx, vars)) {
|
||||
assign_regs(ctx);
|
||||
ctx->data = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ctx->data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,38 @@ void ir_print_proto(const ir_ctx *ctx, ir_ref func_proto, FILE *f)
|
||||
}
|
||||
}
|
||||
|
||||
void ir_print_call_conv(uint32_t flags, FILE *f)
|
||||
{
|
||||
switch (flags & IR_CALL_CONV_MASK) {
|
||||
case IR_CC_BUILTIN:
|
||||
fprintf(f, " __builtin");
|
||||
break;
|
||||
case IR_CC_FASTCALL:
|
||||
fprintf(f, " __fastcall");
|
||||
break;
|
||||
case IR_CC_PRESERVE_NONE:
|
||||
fprintf(f, " __preserve_none");
|
||||
break;
|
||||
#if defined(IR_TARGET_X64)
|
||||
case IR_CC_X86_64_SYSV:
|
||||
fprintf(f, " __sysv");
|
||||
break;
|
||||
case IR_CC_X86_64_MS:
|
||||
fprintf(f, " __win64");
|
||||
break;
|
||||
#elif defined(IR_TARGET_AARCH64)
|
||||
case IR_CC_AARCH64_SYSV:
|
||||
fprintf(f, " __sysv");
|
||||
break;
|
||||
case IR_CC_AARCH64_DARWIN:
|
||||
fprintf(f, " __darwin");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
IR_ASSERT((flags & IR_CALL_CONV_MASK) == IR_CC_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
void ir_print_proto_ex(uint8_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types, FILE *f)
|
||||
{
|
||||
uint32_t j;
|
||||
@@ -35,11 +67,7 @@ void ir_print_proto_ex(uint8_t flags, ir_type ret_type, uint32_t params_count, c
|
||||
fprintf(f, "...");
|
||||
}
|
||||
fprintf(f, "): %s", ir_type_cname[ret_type]);
|
||||
if (flags & IR_FASTCALL_FUNC) {
|
||||
fprintf(f, " __fastcall");
|
||||
} else if (flags & IR_BUILTIN_FUNC) {
|
||||
fprintf(f, " __builtin");
|
||||
}
|
||||
ir_print_call_conv(flags, f);
|
||||
if (flags & IR_CONST_FUNC) {
|
||||
fprintf(f, " __const");
|
||||
} else if (flags & IR_PURE_FUNC) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -82,14 +82,17 @@ enum _ir_reg {
|
||||
IR_GP_REGS(IR_GP_REG_ENUM)
|
||||
IR_FP_REGS(IR_FP_REG_ENUM)
|
||||
IR_REG_NUM,
|
||||
IR_REG_ALL = IR_REG_NUM, /* special name for regset */
|
||||
IR_REG_SET_1, /* special name for regset */
|
||||
IR_REG_SET_2, /* special name for regset */
|
||||
IR_REG_SET_3, /* special name for regset */
|
||||
IR_REG_SET_NUM,
|
||||
};
|
||||
|
||||
#define IR_REG_GP_FIRST IR_REG_R0
|
||||
#define IR_REG_FP_FIRST IR_REG_XMM0
|
||||
#define IR_REG_GP_LAST (IR_REG_FP_FIRST - 1)
|
||||
#define IR_REG_FP_LAST (IR_REG_NUM - 1)
|
||||
#define IR_REG_SCRATCH (IR_REG_NUM) /* special name for regset */
|
||||
#define IR_REG_ALL (IR_REG_NUM + 1) /* special name for regset */
|
||||
|
||||
#define IR_REGSET_64BIT 0
|
||||
|
||||
@@ -113,121 +116,4 @@ enum _ir_reg {
|
||||
#define IR_REG_RSI IR_REG_R6
|
||||
#define IR_REG_RDI IR_REG_R7
|
||||
|
||||
/* Calling Convention */
|
||||
#ifdef _WIN64
|
||||
|
||||
# define IR_REG_INT_RET1 IR_REG_RAX
|
||||
# define IR_REG_FP_RET1 IR_REG_XMM0
|
||||
# define IR_REG_INT_ARGS 4
|
||||
# define IR_REG_FP_ARGS 4
|
||||
# define IR_REG_INT_ARG1 IR_REG_RCX
|
||||
# define IR_REG_INT_ARG2 IR_REG_RDX
|
||||
# define IR_REG_INT_ARG3 IR_REG_R8
|
||||
# define IR_REG_INT_ARG4 IR_REG_R9
|
||||
# define IR_REG_FP_ARG1 IR_REG_XMM0
|
||||
# define IR_REG_FP_ARG2 IR_REG_XMM1
|
||||
# define IR_REG_FP_ARG3 IR_REG_XMM2
|
||||
# define IR_REG_FP_ARG4 IR_REG_XMM3
|
||||
# define IR_MAX_REG_ARGS 4
|
||||
# define IR_SHADOW_ARGS 32 /* Reserved space in bytes - "home space" or "shadow store" for register arguments */
|
||||
|
||||
# define IR_REGSET_SCRATCH \
|
||||
(IR_REGSET_INTERVAL(IR_REG_RAX, IR_REG_RDX) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_R8, IR_REG_R11) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_XMM0, IR_REG_XMM5))
|
||||
|
||||
# define IR_REGSET_PRESERVED \
|
||||
(IR_REGSET(IR_REG_RBX) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_RBP, IR_REG_RDI) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_R12, IR_REG_R15) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_XMM6, IR_REG_XMM15))
|
||||
|
||||
#elif defined(IR_TARGET_X64)
|
||||
|
||||
# define IR_REG_INT_RET1 IR_REG_RAX
|
||||
# define IR_REG_FP_RET1 IR_REG_XMM0
|
||||
# define IR_REG_INT_ARGS 6
|
||||
# define IR_REG_FP_ARGS 8
|
||||
# define IR_REG_INT_ARG1 IR_REG_RDI
|
||||
# define IR_REG_INT_ARG2 IR_REG_RSI
|
||||
# define IR_REG_INT_ARG3 IR_REG_RDX
|
||||
# define IR_REG_INT_ARG4 IR_REG_RCX
|
||||
# define IR_REG_INT_ARG5 IR_REG_R8
|
||||
# define IR_REG_INT_ARG6 IR_REG_R9
|
||||
# define IR_REG_FP_ARG1 IR_REG_XMM0
|
||||
# define IR_REG_FP_ARG2 IR_REG_XMM1
|
||||
# define IR_REG_FP_ARG3 IR_REG_XMM2
|
||||
# define IR_REG_FP_ARG4 IR_REG_XMM3
|
||||
# define IR_REG_FP_ARG5 IR_REG_XMM4
|
||||
# define IR_REG_FP_ARG6 IR_REG_XMM5
|
||||
# define IR_REG_FP_ARG7 IR_REG_XMM6
|
||||
# define IR_REG_FP_ARG8 IR_REG_XMM7
|
||||
# define IR_MAX_REG_ARGS 14
|
||||
# define IR_SHADOW_ARGS 0
|
||||
|
||||
# define IR_REG_VARARG_FP_REGS IR_REG_RAX /* hidden argument to specify the number of vector registers used */
|
||||
|
||||
# define IR_REGSET_SCRATCH \
|
||||
(IR_REGSET_INTERVAL(IR_REG_RAX, IR_REG_RDX) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_RSI, IR_REG_RDI) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_R8, IR_REG_R11) \
|
||||
| IR_REGSET_FP)
|
||||
|
||||
# define IR_REGSET_PRESERVED \
|
||||
(IR_REGSET(IR_REG_RBX) \
|
||||
| IR_REGSET(IR_REG_RBP) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_R12, IR_REG_R15))
|
||||
|
||||
typedef struct _ir_va_list {
|
||||
uint32_t gp_offset;
|
||||
uint32_t fp_offset;
|
||||
void *overflow_arg_area;
|
||||
void *reg_save_area;
|
||||
} ir_va_list;
|
||||
|
||||
#elif defined(IR_TARGET_X86)
|
||||
|
||||
# define IR_REG_INT_RET1 IR_REG_RAX
|
||||
# define IR_REG_INT_RET2 IR_REG_RDX
|
||||
# define IR_REG_INT_ARGS 0
|
||||
# define IR_REG_FP_ARGS 0
|
||||
|
||||
# define IR_HAVE_FASTCALL 1
|
||||
# define IR_REG_INT_FCARGS 2
|
||||
# define IR_REG_FP_FCARGS 0
|
||||
# define IR_REG_INT_FCARG1 IR_REG_RCX
|
||||
# define IR_REG_INT_FCARG2 IR_REG_RDX
|
||||
# define IR_MAX_REG_ARGS 2
|
||||
# define IR_SHADOW_ARGS 0
|
||||
|
||||
# define IR_REGSET_SCRATCH \
|
||||
(IR_REGSET_INTERVAL(IR_REG_RAX, IR_REG_RDX) | IR_REGSET_FP)
|
||||
|
||||
# define IR_REGSET_PRESERVED \
|
||||
(IR_REGSET(IR_REG_RBX) \
|
||||
| IR_REGSET(IR_REG_RBP) \
|
||||
| IR_REGSET_INTERVAL(IR_REG_RSI, IR_REG_RDI))
|
||||
|
||||
#else
|
||||
# error "Unsupported target architecture"
|
||||
#endif
|
||||
|
||||
typedef struct _ir_tmp_reg {
|
||||
union {
|
||||
uint8_t num;
|
||||
int8_t reg;
|
||||
};
|
||||
uint8_t type;
|
||||
int8_t start;
|
||||
int8_t end;
|
||||
} ir_tmp_reg;
|
||||
|
||||
struct _ir_target_constraints {
|
||||
int8_t def_reg;
|
||||
uint8_t tmps_count;
|
||||
uint8_t hints_count;
|
||||
ir_tmp_reg tmp_regs[3];
|
||||
int8_t hints[IR_MAX_REG_ARGS + 3];
|
||||
};
|
||||
|
||||
#endif /* IR_X86_H */
|
||||
|
||||
Reference in New Issue
Block a user