1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00
IR commit: 40cd6ad28c376cf006c360f39d8aeff6d6e7bf78
This commit is contained in:
Dmitry Stogov
2026-01-12 21:23:38 +03:00
committed by GitHub
parent 290ebf13e1
commit 098b1f89bd
11 changed files with 1756 additions and 1660 deletions

View File

@@ -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

View File

@@ -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 */

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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 */