From e95526fdfb08375c39750be7512e1850fc605ad4 Mon Sep 17 00:00:00 2001 From: Klaus Treichel Date: Sat, 31 Oct 2009 15:57:28 +0100 Subject: [PATCH] Add support for the alloca opcode on X86_64. Changes based on a patch from Peter Lobsinger --- ChangeLog | 11 +++++ jit/jit-rules-x86-64.c | 86 ++++++++++++++++++++++++++++++---------- jit/jit-rules-x86-64.h | 14 +++++++ jit/jit-rules-x86-64.ins | 10 +++++ 4 files changed, 101 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index e765f0f..b923174 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,17 @@ * jit/jit-compile.c (_JIT_RESULT_TO_OBJECT, _JIT_RESULT_FROM_OBJECT): Fix compiler warnings on systems where sizeof(int) != sizeof(void *) + * jit/jit-rules-x86-64.c (fixup_alloca): Added to handle alloca + fixups with param area enabled. + (_jit_gen_epilog): Generate the epilog differenty if the stackpointer + was changed during code generation with param area enabled. + + * jit/jit-rules-x86-64.h: Add the alloca_fixups to the + extra_gen_state. + + * jit/jit-rules-x86-64.ins: Add support for JIT_OP_ALLOCA. + (alloca support based on a patch from Peter Lobsinger, thanks) + 2009-10-30 Aleksey Demakov * include/jit/jit-function.h, jit/jit-function.c diff --git a/jit/jit-rules-x86-64.c b/jit/jit-rules-x86-64.c index 52ba8ed..155d201 100644 --- a/jit/jit-rules-x86-64.c +++ b/jit/jit-rules-x86-64.c @@ -1327,6 +1327,47 @@ jump_to_epilog(jit_gencode_t gen, unsigned char *inst, jit_block_t block) return inst; } +/* + * fixup a register being alloca'd to by accounting for the param area + */ +static unsigned char * +fixup_alloca(jit_gencode_t gen, unsigned char *inst, int reg) +{ +#ifdef JIT_USE_PARAM_AREA + jit_int fixup; + jit_int temp; + + /* + * emit the instruction and then replace the imm section of op with + * the fixup. + * NOTE: We are using the temp variable here to avoid a compiler + * warning and the temp value to make sure that an instruction with + * a 32 bit immediate is emitted. The temp value in the instruction + * will be replaced by the fixup + */ + temp = 1234567; + x86_64_add_reg_imm_size(inst, reg, temp, 8); + + /* Make inst pointing to the 32bit immediate in the instruction */ + inst -= 4; + + /* calculalte the fixup */ + if (gen->alloca_fixup) + { + fixup = _JIT_CALC_FIXUP(gen->alloca_fixup, inst); + } + else + { + fixup = 0; + } + gen->alloca_fixup = (void *)inst; + x86_imm_emit32(inst, fixup); +#else /* !JIT_USE_PARAM_AREA */ + /* alloca fixup is not needed if the param area is not used */ +#endif /* JIT_USE_PARAM_AREA */ + return inst; +} + /* * Compare a xmm register with an immediate value. */ @@ -2469,27 +2510,22 @@ _jit_gen_epilog(jit_gencode_t gen, jit_function_t func) } gen->epilog_fixup = 0; - /* Restore the used callee saved registers */ -#ifdef JIT_USE_PARAM_AREA - if(func->builder->param_area_size > 0) + /* Perform fixups on any alloca calls */ + fixup = (jit_int *)(gen->alloca_fixup); + while (fixup != 0) { - current_offset = func->builder->param_area_size; - } - else - { - current_offset = 0; - } - for(reg = 0; reg <= 14; ++reg) - { - if(jit_reg_is_used(gen->touched, reg) && - (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0) + next = (jit_int *)_JIT_CALC_NEXT_FIXUP(fixup, fixup[0]); + fixup[0] = func->builder->param_area_size; + if(DEBUG_FIXUPS) { - x86_64_mov_reg_membase_size(inst, _jit_reg_info[reg].cpu_reg, - X86_64_RSP, current_offset, 8); - current_offset += 8; + fprintf(stderr, "Fixup Param Area Size: %lx, Value: %x\n", + (jit_nint)fixup, fixup[0]); } + fixup = next; } -#else /* !JIT_USE_PARAM_AREA */ + gen->alloca_fixup = 0; + + /* Restore the used callee saved registers */ if(gen->stack_changed) { int frame_size = func->builder->frame_size; @@ -2520,26 +2556,36 @@ _jit_gen_epilog(jit_gencode_t gen, jit_function_t func) (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0) { x86_64_mov_reg_membase_size(inst, _jit_reg_info[reg].cpu_reg, - X86_64_RBP, current_offset, 8); + X86_64_RBP, current_offset, 8); current_offset += 8; } } } else { +#ifdef JIT_USE_PARAM_AREA + if(func->builder->param_area_size > 0) + { + current_offset = func->builder->param_area_size; + } + else + { + current_offset = 0; + } +#else /* !JIT_USE_PARAM_AREA */ current_offset = 0; +#endif /* !JIT_USE_PARAM_AREA */ for(reg = 0; reg <= 14; ++reg) { if(jit_reg_is_used(gen->touched, reg) && (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0) { x86_64_mov_reg_membase_size(inst, _jit_reg_info[reg].cpu_reg, - X86_64_RSP, current_offset, 8); + X86_64_RSP, current_offset, 8); current_offset += 8; } } } -#endif /* !JIT_USE_PARAM_AREA */ /* Restore stackpointer and frame register */ x86_64_mov_reg_reg_size(inst, X86_64_RSP, X86_64_RBP, 8); diff --git a/jit/jit-rules-x86-64.h b/jit/jit-rules-x86-64.h index 569d429..37b896d 100644 --- a/jit/jit-rules-x86-64.h +++ b/jit/jit-rules-x86-64.h @@ -109,6 +109,20 @@ extern "C" { */ #define JIT_ALIGN_OVERRIDES 1 +/* + * Extra state information that is added to the "jit_gencode" structure. + */ + +#define jit_extra_gen_state \ + void *alloca_fixup + +#define jit_extra_gen_init(gen) \ + do { \ + (gen)->alloca_fixup = 0; \ + } while (0) + +#define jit_extra_gen_cleanup(gen) do { ; } while (0) + /* * Parameter passing rules. */ diff --git a/jit/jit-rules-x86-64.ins b/jit/jit-rules-x86-64.ins index cce6118..f8a1096 100644 --- a/jit/jit-rules-x86-64.ins +++ b/jit/jit-rules-x86-64.ins @@ -3167,6 +3167,16 @@ JIT_OP_MEMSET: ternary inst = x86_64_call_code(inst, (jit_nint)jit_memset); } +JIT_OP_ALLOCA: + [reg] -> { + x86_64_add_reg_imm_size(inst, $1, 15, 8); + x86_64_and_reg_imm_size(inst, $1, ~15, 8); + x86_64_sub_reg_reg_size(inst, X86_64_RSP, $1, 8); + x86_64_mov_reg_reg_size(inst, $1, X86_64_RSP, 8); + inst = fixup_alloca(gen, inst, $1); + gen->stack_changed = 1; +} + JIT_OP_JUMP_TABLE: ternary, branch [reg, imm, imm, scratch reg, space("64")] -> { unsigned char *patch_jump_table; -- 2.47.3