Optimise out redundant uOPs, where the output register is never read.
This commit is contained in:
parent
84622584e2
commit
3f2d9ecf87
4 changed files with 200 additions and 57 deletions
|
|
@ -21,6 +21,8 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block)
|
||||||
int jump_target_at_end = -1;
|
int jump_target_at_end = -1;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
codegen_reg_mark_as_required();
|
||||||
|
codegen_reg_process_dead_list(ir);
|
||||||
block_write_data = codeblock_allocator_get_ptr(block->head_mem_block);
|
block_write_data = codeblock_allocator_get_ptr(block->head_mem_block);
|
||||||
block_pos = 0;
|
block_pos = 0;
|
||||||
codegen_backend_prologue(block);
|
codegen_backend_prologue(block);
|
||||||
|
|
@ -45,6 +47,9 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((uop->type & UOP_MASK) == UOP_INVALID)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (uop->type & UOP_TYPE_PARAMS_REGS)
|
if (uop->type & UOP_TYPE_PARAMS_REGS)
|
||||||
{
|
{
|
||||||
codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b, uop->src_reg_c);
|
codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b, uop->src_reg_c);
|
||||||
|
|
|
||||||
|
|
@ -312,6 +312,8 @@
|
||||||
|
|
||||||
#define UOP_MAX 0xc6
|
#define UOP_MAX 0xc6
|
||||||
|
|
||||||
|
#define UOP_INVALID 0xff
|
||||||
|
|
||||||
#define UOP_MASK 0xffff
|
#define UOP_MASK 0xffff
|
||||||
|
|
||||||
typedef struct uop_t
|
typedef struct uop_t
|
||||||
|
|
@ -338,7 +340,7 @@ typedef struct ir_data_t
|
||||||
int wr_pos;
|
int wr_pos;
|
||||||
} ir_data_t;
|
} ir_data_t;
|
||||||
|
|
||||||
static inline uop_t *uop_alloc(ir_data_t *ir)
|
static inline uop_t *uop_alloc(ir_data_t *ir, uint32_t uop_type)
|
||||||
{
|
{
|
||||||
uop_t *uop;
|
uop_t *uop;
|
||||||
|
|
||||||
|
|
@ -354,6 +356,9 @@ static inline uop_t *uop_alloc(ir_data_t *ir)
|
||||||
|
|
||||||
uop->jump_list_next = -1;
|
uop->jump_list_next = -1;
|
||||||
|
|
||||||
|
if (uop_type & (UOP_TYPE_BARRIER | UOP_TYPE_ORDER_BARRIER))
|
||||||
|
codegen_reg_mark_as_required();
|
||||||
|
|
||||||
return uop;
|
return uop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -366,7 +371,7 @@ static inline void uop_set_jump_dest(ir_data_t *ir, int jump_uop)
|
||||||
|
|
||||||
static inline int uop_gen(uint32_t uop_type, ir_data_t *ir)
|
static inline int uop_gen(uint32_t uop_type, ir_data_t *ir)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
|
|
||||||
|
|
@ -375,7 +380,7 @@ static inline int uop_gen(uint32_t uop_type, ir_data_t *ir)
|
||||||
|
|
||||||
static inline int uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int src_reg_a)
|
static inline int uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int src_reg_a)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
|
|
@ -385,7 +390,7 @@ static inline int uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int src_reg
|
||||||
|
|
||||||
static inline void uop_gen_reg_src1_arg(uint32_t uop_type, ir_data_t *ir, int arg, int src_reg_a)
|
static inline void uop_gen_reg_src1_arg(uint32_t uop_type, ir_data_t *ir, int arg, int src_reg_a)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
|
|
@ -393,7 +398,7 @@ static inline void uop_gen_reg_src1_arg(uint32_t uop_type, ir_data_t *ir, int ar
|
||||||
|
|
||||||
static inline int uop_gen_reg_src1_imm(uint32_t uop_type, ir_data_t *ir, int src_reg, uint32_t imm)
|
static inline int uop_gen_reg_src1_imm(uint32_t uop_type, ir_data_t *ir, int src_reg, uint32_t imm)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg);
|
uop->src_reg_a = codegen_reg_read(src_reg);
|
||||||
|
|
@ -404,86 +409,86 @@ static inline int uop_gen_reg_src1_imm(uint32_t uop_type, ir_data_t *ir, int src
|
||||||
|
|
||||||
static inline void uop_gen_reg_dst_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, uint32_t imm)
|
static inline void uop_gen_reg_dst_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, uint32_t imm)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1);
|
||||||
uop->imm_data = imm;
|
uop->imm_data = imm;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void uop_gen_reg_dst_pointer(uint32_t uop_type, ir_data_t *ir, int dest_reg, void *p)
|
static inline void uop_gen_reg_dst_pointer(uint32_t uop_type, ir_data_t *ir, int dest_reg, void *p)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1);
|
||||||
uop->p = p;
|
uop->p = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void uop_gen_reg_dst_src1(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg)
|
static inline void uop_gen_reg_dst_src1(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg);
|
uop->src_reg_a = codegen_reg_read(src_reg);
|
||||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void uop_gen_reg_dst_src1_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, uint32_t imm)
|
static inline void uop_gen_reg_dst_src1_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, uint32_t imm)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1);
|
||||||
uop->imm_data = imm;
|
uop->imm_data = imm;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void uop_gen_reg_dst_src2(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b)
|
static inline void uop_gen_reg_dst_src2(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
uop->src_reg_b = codegen_reg_read(src_reg_b);
|
uop->src_reg_b = codegen_reg_read(src_reg_b);
|
||||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void uop_gen_reg_dst_src2_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, uint32_t imm)
|
static inline void uop_gen_reg_dst_src2_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, uint32_t imm)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
uop->src_reg_b = codegen_reg_read(src_reg_b);
|
uop->src_reg_b = codegen_reg_read(src_reg_b);
|
||||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1);
|
||||||
uop->imm_data = imm;
|
uop->imm_data = imm;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void uop_gen_reg_dst_src3(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, int src_reg_c)
|
static inline void uop_gen_reg_dst_src3(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, int src_reg_c)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
uop->src_reg_b = codegen_reg_read(src_reg_b);
|
uop->src_reg_b = codegen_reg_read(src_reg_b);
|
||||||
uop->src_reg_c = codegen_reg_read(src_reg_c);
|
uop->src_reg_c = codegen_reg_read(src_reg_c);
|
||||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void uop_gen_reg_dst_src_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg, uint32_t imm)
|
static inline void uop_gen_reg_dst_src_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg, uint32_t imm)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg);
|
uop->src_reg_a = codegen_reg_read(src_reg);
|
||||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1);
|
||||||
uop->imm_data = imm;
|
uop->imm_data = imm;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int uop_gen_reg_src2(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b)
|
static inline int uop_gen_reg_src2(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
|
|
@ -494,7 +499,7 @@ static inline int uop_gen_reg_src2(uint32_t uop_type, ir_data_t *ir, int src_reg
|
||||||
|
|
||||||
static inline void uop_gen_reg_src2_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, uint32_t imm)
|
static inline void uop_gen_reg_src2_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, uint32_t imm)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
|
|
@ -504,7 +509,7 @@ static inline void uop_gen_reg_src2_imm(uint32_t uop_type, ir_data_t *ir, int sr
|
||||||
|
|
||||||
static inline void uop_gen_reg_src3(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, int src_reg_c)
|
static inline void uop_gen_reg_src3(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, int src_reg_c)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
|
|
@ -514,7 +519,7 @@ static inline void uop_gen_reg_src3(uint32_t uop_type, ir_data_t *ir, int src_re
|
||||||
|
|
||||||
static inline void uop_gen_reg_src3_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, int src_reg_c, uint32_t imm)
|
static inline void uop_gen_reg_src3_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, int src_reg_c, uint32_t imm)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
|
|
@ -525,7 +530,7 @@ static inline void uop_gen_reg_src3_imm(uint32_t uop_type, ir_data_t *ir, int sr
|
||||||
|
|
||||||
static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm)
|
static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->imm_data = imm;
|
uop->imm_data = imm;
|
||||||
|
|
@ -533,7 +538,7 @@ static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm)
|
||||||
|
|
||||||
static inline void uop_gen_pointer(uint32_t uop_type, ir_data_t *ir, void *p)
|
static inline void uop_gen_pointer(uint32_t uop_type, ir_data_t *ir, void *p)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->p = p;
|
uop->p = p;
|
||||||
|
|
@ -541,7 +546,7 @@ static inline void uop_gen_pointer(uint32_t uop_type, ir_data_t *ir, void *p)
|
||||||
|
|
||||||
static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p, uint32_t imm)
|
static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p, uint32_t imm)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->p = p;
|
uop->p = p;
|
||||||
|
|
@ -550,7 +555,7 @@ static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p
|
||||||
|
|
||||||
static inline void uop_gen_reg_src_pointer(uint32_t uop_type, ir_data_t *ir, int src_reg_a, void *p)
|
static inline void uop_gen_reg_src_pointer(uint32_t uop_type, ir_data_t *ir, int src_reg_a, void *p)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
|
|
@ -559,7 +564,7 @@ static inline void uop_gen_reg_src_pointer(uint32_t uop_type, ir_data_t *ir, int
|
||||||
|
|
||||||
static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, void *p, uint32_t imm)
|
static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, void *p, uint32_t imm)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
|
|
@ -569,7 +574,7 @@ static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir,
|
||||||
|
|
||||||
static inline void uop_gen_reg_src2_pointer(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, void *p)
|
static inline void uop_gen_reg_src2_pointer(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, void *p)
|
||||||
{
|
{
|
||||||
uop_t *uop = uop_alloc(ir);
|
uop_t *uop = uop_alloc(ir, uop_type);
|
||||||
|
|
||||||
uop->type = uop_type;
|
uop->type = uop_type;
|
||||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
#include "codegen_ir_defs.h"
|
#include "codegen_ir_defs.h"
|
||||||
#include "codegen_reg.h"
|
#include "codegen_reg.h"
|
||||||
|
|
||||||
|
uint16_t reg_dead_list = 0;
|
||||||
|
|
||||||
uint8_t reg_last_version[IREG_COUNT];
|
uint8_t reg_last_version[IREG_COUNT];
|
||||||
uint8_t reg_version_refcount[IREG_COUNT][256];
|
reg_version_t reg_version[IREG_COUNT][256];
|
||||||
|
|
||||||
ir_reg_t invalid_ir_reg = {IREG_INVALID};
|
ir_reg_t invalid_ir_reg = {IREG_INVALID};
|
||||||
|
|
||||||
|
|
@ -175,6 +177,19 @@ struct
|
||||||
[IREG_temp1d] = {REG_DOUBLE, (void *)48, REG_FP, REG_VOLATILE},
|
[IREG_temp1d] = {REG_DOUBLE, (void *)48, REG_FP, REG_VOLATILE},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void codegen_reg_mark_as_required()
|
||||||
|
{
|
||||||
|
int reg;
|
||||||
|
|
||||||
|
for (reg = 0; reg < IREG_COUNT; reg++)
|
||||||
|
{
|
||||||
|
int last_version = reg_last_version[reg];
|
||||||
|
|
||||||
|
if (last_version > 0 && ireg_data[reg].is_volatile == REG_PERMANENT)
|
||||||
|
reg_version[reg][last_version].flags |= REG_FLAGS_REQUIRED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int reg_is_native_size(ir_reg_t ir_reg)
|
static int reg_is_native_size(ir_reg_t ir_reg)
|
||||||
{
|
{
|
||||||
int native_size = ireg_data[IREG_GET_REG(ir_reg.reg)].native_size;
|
int native_size = ireg_data[IREG_GET_REG(ir_reg.reg)].native_size;
|
||||||
|
|
@ -220,7 +235,7 @@ void codegen_reg_reset()
|
||||||
for (c = 0; c < IREG_COUNT; c++)
|
for (c = 0; c < IREG_COUNT; c++)
|
||||||
{
|
{
|
||||||
reg_last_version[c] = 0;
|
reg_last_version[c] = 0;
|
||||||
reg_version_refcount[c][0] = 0;
|
reg_version[c][0].refcount = 0;
|
||||||
}
|
}
|
||||||
for (c = 0; c < CODEGEN_HOST_REGS; c++)
|
for (c = 0; c < CODEGEN_HOST_REGS; c++)
|
||||||
{
|
{
|
||||||
|
|
@ -232,6 +247,8 @@ void codegen_reg_reset()
|
||||||
host_fp_reg_set.regs[c] = invalid_ir_reg;
|
host_fp_reg_set.regs[c] = invalid_ir_reg;
|
||||||
host_fp_reg_set.dirty[c] = 0;
|
host_fp_reg_set.dirty[c] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reg_dead_list = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ir_reg_is_invalid(ir_reg_t ir_reg)
|
static inline int ir_reg_is_invalid(ir_reg_t ir_reg)
|
||||||
|
|
@ -239,9 +256,9 @@ static inline int ir_reg_is_invalid(ir_reg_t ir_reg)
|
||||||
return (IREG_GET_REG(ir_reg.reg) == IREG_INVALID);
|
return (IREG_GET_REG(ir_reg.reg) == IREG_INVALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ir_get_get_refcount(ir_reg_t ir_reg)
|
static inline int ir_get_refcount(ir_reg_t ir_reg)
|
||||||
{
|
{
|
||||||
return reg_version_refcount[IREG_GET_REG(ir_reg.reg)][ir_reg.version];
|
return reg_version[IREG_GET_REG(ir_reg.reg)][ir_reg.version].refcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline host_reg_set_t *get_reg_set(ir_reg_t ir_reg)
|
static inline host_reg_set_t *get_reg_set(ir_reg_t ir_reg)
|
||||||
|
|
@ -342,7 +359,7 @@ static void codegen_reg_writeback(host_reg_set_t *reg_set, codeblock_t *block, i
|
||||||
int ir_reg = IREG_GET_REG(reg_set->regs[c].reg);
|
int ir_reg = IREG_GET_REG(reg_set->regs[c].reg);
|
||||||
void *p = ireg_data[ir_reg].p;
|
void *p = ireg_data[ir_reg].p;
|
||||||
|
|
||||||
if (!reg_version_refcount[ir_reg][reg_set->regs[c].version] &&
|
if (!reg_version[ir_reg][reg_set->regs[c].version].refcount &&
|
||||||
ireg_data[ir_reg].is_volatile)
|
ireg_data[ir_reg].is_volatile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -463,10 +480,30 @@ static void alloc_dest_reg(ir_reg_t ir_reg, int dest_reference)
|
||||||
{
|
{
|
||||||
if (IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg))
|
if (IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg))
|
||||||
{
|
{
|
||||||
if (reg_set->regs[c].version == ir_reg.version || (reg_set->regs[c].version == (ir_reg.version-1) && reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version] == dest_reference))
|
if (reg_set->regs[c].version == ir_reg.version)
|
||||||
|
{
|
||||||
reg_set->locked |= (1 << c);
|
reg_set->locked |= (1 << c);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
/*The immediate prior version may have been
|
||||||
|
optimised out, so search backwards to find the
|
||||||
|
last valid version*/
|
||||||
|
int prev_version = ir_reg.version-1;
|
||||||
|
// pclog("prev_version search from %i\n", prev_version);
|
||||||
|
while (prev_version >= 0)
|
||||||
|
{
|
||||||
|
reg_version_t *regv = ®_version[IREG_GET_REG(reg_set->regs[c].reg)][prev_version];
|
||||||
|
|
||||||
|
if (!(regv->flags & REG_FLAGS_DEAD) && regv->refcount == dest_reference)
|
||||||
|
{
|
||||||
|
reg_set->locked |= (1 << c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prev_version--;
|
||||||
|
}
|
||||||
fatal("codegen_reg_alloc_register - host_regs[c].version != dest_reg_a.version %i,%i %i\n", reg_set->regs[c].version, ir_reg.version, dest_reference);
|
fatal("codegen_reg_alloc_register - host_regs[c].version != dest_reg_a.version %i,%i %i\n", reg_set->regs[c].version, ir_reg.version, dest_reference);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -513,7 +550,13 @@ ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, in
|
||||||
if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_set->regs[c].version == ir_reg.version)
|
if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_set->regs[c].version == ir_reg.version)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version])
|
if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_set->regs[c].version <= ir_reg.version)
|
||||||
|
{
|
||||||
|
reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount)
|
||||||
fatal("codegen_reg_alloc_read_reg - version mismatch!\n");
|
fatal("codegen_reg_alloc_read_reg - version mismatch!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -522,7 +565,7 @@ ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, in
|
||||||
/*No unused registers. Search for an unlocked register with no pending reads*/
|
/*No unused registers. Search for an unlocked register with no pending reads*/
|
||||||
for (c = 0; c < reg_set->nr_regs; c++)
|
for (c = 0; c < reg_set->nr_regs; c++)
|
||||||
{
|
{
|
||||||
if (!(reg_set->locked & (1 << c)) && !ir_get_get_refcount(reg_set->regs[c]))
|
if (!(reg_set->locked & (1 << c)) && IREG_GET_REG(reg_set->regs[c].reg) != IREG_INVALID && !ir_get_refcount(reg_set->regs[c]))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c == reg_set->nr_regs)
|
if (c == reg_set->nr_regs)
|
||||||
|
|
@ -548,13 +591,13 @@ ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, in
|
||||||
// else
|
// else
|
||||||
// pclog(" already loaded %i\n", c);
|
// pclog(" already loaded %i\n", c);
|
||||||
|
|
||||||
reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version]--;
|
reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount--;
|
||||||
if (reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version] == (uint8_t)-1)
|
if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount == (uint8_t)-1)
|
||||||
fatal("codegen_reg_alloc_read_reg - refcount < 0\n");
|
fatal("codegen_reg_alloc_read_reg - refcount < 0\n");
|
||||||
|
|
||||||
if (host_reg_idx)
|
if (host_reg_idx)
|
||||||
*host_reg_idx = c;
|
*host_reg_idx = c;
|
||||||
// pclog(" codegen_reg_alloc_read_reg: %i.%i %i %02x.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c], host_regs[c].reg,host_regs[c].version, c);
|
// pclog(" codegen_reg_alloc_read_reg: %i.%i %i %02x.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c], reg_set->regs[c].reg,reg_set->regs[c].version, c);
|
||||||
return reg_set->reg_list[c] | IREG_GET_SIZE(ir_reg.reg);
|
return reg_set->reg_list[c] | IREG_GET_SIZE(ir_reg.reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -570,11 +613,11 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg)
|
||||||
|
|
||||||
parent_reg.reg = IREG_GET_REG(ir_reg.reg) | IREG_SIZE_L;
|
parent_reg.reg = IREG_GET_REG(ir_reg.reg) | IREG_SIZE_L;
|
||||||
parent_reg.version = ir_reg.version - 1;
|
parent_reg.version = ir_reg.version - 1;
|
||||||
reg_version_refcount[IREG_GET_REG(ir_reg.reg)][ir_reg.version - 1]++;
|
reg_version[IREG_GET_REG(ir_reg.reg)][ir_reg.version - 1].refcount++;
|
||||||
|
|
||||||
codegen_reg_alloc_read_reg(block, parent_reg, &c);
|
codegen_reg_alloc_read_reg(block, parent_reg, &c);
|
||||||
|
|
||||||
if (IREG_GET_REG(reg_set->regs[c].reg) != IREG_GET_REG(ir_reg.reg) || reg_set->regs[c].version != ir_reg.version-1)
|
if (IREG_GET_REG(reg_set->regs[c].reg) != IREG_GET_REG(ir_reg.reg) || reg_set->regs[c].version > ir_reg.version-1)
|
||||||
fatal("codegen_reg_alloc_write_reg sub_reg - doesn't match %i %02x.%i %02x.%i\n", c,
|
fatal("codegen_reg_alloc_write_reg sub_reg - doesn't match %i %02x.%i %02x.%i\n", c,
|
||||||
reg_set->regs[c].reg,reg_set->regs[c].version,
|
reg_set->regs[c].reg,reg_set->regs[c].version,
|
||||||
ir_reg.reg,ir_reg.version);
|
ir_reg.reg,ir_reg.version);
|
||||||
|
|
@ -591,9 +634,9 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg)
|
||||||
{
|
{
|
||||||
if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg))
|
if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg))
|
||||||
{
|
{
|
||||||
if (reg_set->regs[c].version == ir_reg.version-1)
|
if (reg_set->regs[c].version <= ir_reg.version-1)
|
||||||
{
|
{
|
||||||
if (reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version] != 0)
|
if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount != 0)
|
||||||
fatal("codegen_reg_alloc_write_reg - previous version refcount != 0\n");
|
fatal("codegen_reg_alloc_write_reg - previous version refcount != 0\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -682,3 +725,49 @@ void codegen_reg_flush_invalidate(ir_data_t *ir, codeblock_t *block)
|
||||||
reg_set->dirty[c] = 0;
|
reg_set->dirty[c] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*Process dead register list, and optimise out register versions and uOPs where
|
||||||
|
possible*/
|
||||||
|
void codegen_reg_process_dead_list(ir_data_t *ir)
|
||||||
|
{
|
||||||
|
while (reg_dead_list)
|
||||||
|
{
|
||||||
|
int version = reg_dead_list & 0xff;
|
||||||
|
int reg = reg_dead_list >> 8;
|
||||||
|
reg_version_t *regv = ®_version[reg][version];
|
||||||
|
uop_t *uop = &ir->uops[regv->parent_uop];
|
||||||
|
|
||||||
|
/*Barrier uOPs should be preserved*/
|
||||||
|
if (!(uop->type & (UOP_TYPE_BARRIER | UOP_TYPE_ORDER_BARRIER)))
|
||||||
|
{
|
||||||
|
// pclog(" codegen_process_dead_list: reg=%i version=%i uop=%i\n", reg, version, regv->parent_uop);
|
||||||
|
uop->type = UOP_INVALID;
|
||||||
|
/*Adjust refcounts on source registers. If these drop to
|
||||||
|
zero then those registers can be considered for removal*/
|
||||||
|
if (uop->src_reg_a.reg != IREG_INVALID)
|
||||||
|
{
|
||||||
|
reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_a.reg)][uop->src_reg_a.version];
|
||||||
|
src_regv->refcount--;
|
||||||
|
if (!src_regv->refcount)
|
||||||
|
add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_a.reg), uop->src_reg_a.version);
|
||||||
|
}
|
||||||
|
if (uop->src_reg_b.reg != IREG_INVALID)
|
||||||
|
{
|
||||||
|
reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_b.reg)][uop->src_reg_b.version];
|
||||||
|
src_regv->refcount--;
|
||||||
|
if (!src_regv->refcount)
|
||||||
|
add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_b.reg), uop->src_reg_b.version);
|
||||||
|
}
|
||||||
|
if (uop->src_reg_c.reg != IREG_INVALID)
|
||||||
|
{
|
||||||
|
reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_c.reg)][uop->src_reg_c.version];
|
||||||
|
src_regv->refcount--;
|
||||||
|
if (!src_regv->refcount)
|
||||||
|
add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_c.reg), uop->src_reg_c.version);
|
||||||
|
}
|
||||||
|
regv->flags |= REG_FLAGS_DEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_dead_list = regv->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,36 @@ static inline int ireg_seg_limit_high(x86seg *seg)
|
||||||
}
|
}
|
||||||
|
|
||||||
extern uint8_t reg_last_version[IREG_COUNT];
|
extern uint8_t reg_last_version[IREG_COUNT];
|
||||||
extern uint8_t reg_version_refcount[IREG_COUNT][256];
|
|
||||||
|
/*This version of the register must be calculated, regardless of whether it is
|
||||||
|
apparently required or not. Do not optimise out.*/
|
||||||
|
#define REG_FLAGS_REQUIRED (1 << 0)
|
||||||
|
/*This register and the parent uOP have been optimised out.*/
|
||||||
|
#define REG_FLAGS_DEAD (1 << 1)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/*Refcount of pending reads on this register version*/
|
||||||
|
uint8_t refcount;
|
||||||
|
/*Flags*/
|
||||||
|
uint8_t flags;
|
||||||
|
/*uOP that generated this register version*/
|
||||||
|
uint16_t parent_uop;
|
||||||
|
/*Pointer to next register version in dead register list*/
|
||||||
|
uint16_t next;
|
||||||
|
} reg_version_t;
|
||||||
|
|
||||||
|
extern reg_version_t reg_version[IREG_COUNT][256];
|
||||||
|
|
||||||
|
/*Head of dead register list; a list of register versions that are not used and
|
||||||
|
can be optimised out*/
|
||||||
|
extern uint16_t reg_dead_list;
|
||||||
|
|
||||||
|
static inline void add_to_dead_list(reg_version_t *regv, int reg, int version)
|
||||||
|
{
|
||||||
|
regv->next = reg_dead_list;
|
||||||
|
reg_dead_list = version | (reg << 8);
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
@ -289,37 +318,50 @@ typedef uint16_t ir_host_reg_t;
|
||||||
static inline ir_reg_t codegen_reg_read(int reg)
|
static inline ir_reg_t codegen_reg_read(int reg)
|
||||||
{
|
{
|
||||||
ir_reg_t ireg;
|
ir_reg_t ireg;
|
||||||
|
reg_version_t *version;
|
||||||
|
|
||||||
if (IREG_GET_REG(reg) == IREG_INVALID)
|
if (IREG_GET_REG(reg) == IREG_INVALID)
|
||||||
fatal("codegen_reg_read - IREG_INVALID\n");
|
fatal("codegen_reg_read - IREG_INVALID\n");
|
||||||
|
|
||||||
ireg.reg = reg;
|
ireg.reg = reg;
|
||||||
ireg.version = reg_last_version[IREG_GET_REG(reg)];
|
ireg.version = reg_last_version[IREG_GET_REG(reg)];
|
||||||
reg_version_refcount[IREG_GET_REG(ireg.reg)][ireg.version]++;
|
version = ®_version[IREG_GET_REG(ireg.reg)][ireg.version];
|
||||||
if (!reg_version_refcount[IREG_GET_REG(ireg.reg)][ireg.version])
|
version->flags = 0;
|
||||||
|
version->refcount++;
|
||||||
|
if (!version->refcount)
|
||||||
fatal("codegen_reg_read - refcount overflow\n");
|
fatal("codegen_reg_read - refcount overflow\n");
|
||||||
else if (reg_version_refcount[IREG_GET_REG(ireg.reg)][ireg.version] > REG_VERSION_MAX)
|
else if (version->refcount > REG_VERSION_MAX)
|
||||||
CPU_BLOCK_END();
|
CPU_BLOCK_END();
|
||||||
|
// pclog("codegen_reg_read: %i %i %i\n", reg & IREG_REG_MASK, ireg.version, reg_version_refcount[IREG_GET_REG(ireg.reg)][ireg.version]);
|
||||||
return ireg;
|
return ireg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ir_reg_t codegen_reg_write(int reg)
|
static inline ir_reg_t codegen_reg_write(int reg, int uop_nr)
|
||||||
{
|
{
|
||||||
ir_reg_t ireg;
|
ir_reg_t ireg;
|
||||||
|
int last_version = reg_last_version[IREG_GET_REG(reg)];
|
||||||
|
reg_version_t *version;
|
||||||
|
|
||||||
if (IREG_GET_REG(reg) == IREG_INVALID)
|
if (IREG_GET_REG(reg) == IREG_INVALID)
|
||||||
fatal("codegen_reg_write - IREG_INVALID\n");
|
fatal("codegen_reg_write - IREG_INVALID\n");
|
||||||
|
|
||||||
ireg.reg = reg;
|
ireg.reg = reg;
|
||||||
ireg.version = reg_last_version[IREG_GET_REG(reg)] + 1;
|
ireg.version = last_version + 1;
|
||||||
|
|
||||||
|
if (IREG_GET_REG(reg) > IREG_EBX && last_version && !reg_version[IREG_GET_REG(reg)][last_version].refcount &&
|
||||||
|
!(reg_version[IREG_GET_REG(reg)][last_version].flags & REG_FLAGS_REQUIRED))
|
||||||
|
add_to_dead_list(®_version[IREG_GET_REG(reg)][last_version], IREG_GET_REG(reg), last_version);
|
||||||
|
|
||||||
reg_last_version[IREG_GET_REG(reg)]++;
|
reg_last_version[IREG_GET_REG(reg)]++;
|
||||||
if (!reg_last_version[IREG_GET_REG(reg)])
|
if (!reg_last_version[IREG_GET_REG(reg)])
|
||||||
fatal("codegen_reg_write - version overflow\n");
|
fatal("codegen_reg_write - version overflow\n");
|
||||||
else if (reg_last_version[IREG_GET_REG(reg)] > REG_VERSION_MAX)
|
else if (reg_last_version[IREG_GET_REG(reg)] > REG_VERSION_MAX)
|
||||||
CPU_BLOCK_END();
|
CPU_BLOCK_END();
|
||||||
reg_version_refcount[IREG_GET_REG(reg)][ireg.version] = 0;
|
version = ®_version[IREG_GET_REG(reg)][ireg.version];
|
||||||
|
version->refcount = 0;
|
||||||
|
version->flags = 0;
|
||||||
|
version->parent_uop = uop_nr;
|
||||||
|
// pclog("codegen_reg_write: %i\n", reg & IREG_REG_MASK);
|
||||||
return ireg;
|
return ireg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,4 +379,6 @@ void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_
|
||||||
ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, int *host_reg_idx);
|
ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, int *host_reg_idx);
|
||||||
ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg);
|
ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg);
|
||||||
|
|
||||||
|
void codegen_reg_mark_as_required();
|
||||||
|
void codegen_reg_process_dead_list(struct ir_data_t *ir);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue