Browse Source

Implement a constant pool for ARM, which gets complicated constants out


			
			
				cache-refactoring
			
			
		
Rhys Weatherley 21 years ago
parent
commit
31276bc5eb
  1. 5
      ChangeLog
  2. 42
      jit/jit-gen-arm.c
  3. 1
      jit/jit-gen-arm.h
  4. 385
      jit/jit-rules-arm.c
  5. 18
      jit/jit-rules-arm.h
  6. 59
      jit/jit-rules-arm.sel

5
ChangeLog

@ -30,6 +30,11 @@
* jit/jit-rules-arm.c: ARM parameters cannot be split between
registers and the stack.
* jit/jit-gen-arm.c, jit/jit-gen-arm.h, jit/jit-rules-arm.c,
jit/jit-rules-arm.h, jit/jit-rules-arm.sel: implement a
constant pool for ARM, which gets complicated constants out
of the main stream of execution.
2004-06-08 Miroslaw Dobrzanski-Neumann <mne@mosaic-ag.com>
* jit/jit-alloc.c: fix ROUND_END_PTR so that it adds the size

42
jit/jit-gen-arm.c

@ -128,6 +128,48 @@ arm_inst_ptr _arm_mov_reg_imm
return inst;
}
int arm_is_complex_imm(int value)
{
if(value > -256 && value < 256)
{
return 0;
}
else if((value & 0x000000FF) == value)
{
return 0;
}
else if((value & 0x0000FF00) == value)
{
return 0;
}
else if((value & 0x00FF0000) == value)
{
return 0;
}
else if((value & 0xFF000000) == value)
{
return 0;
}
value = ~value;
if((value & 0x000000FF) == value)
{
return 0;
}
else if((value & 0x0000FF00) == value)
{
return 0;
}
else if((value & 0x00FF0000) == value)
{
return 0;
}
else if((value & 0xFF000000) == value)
{
return 0;
}
return 1;
}
arm_inst_ptr _arm_alu_reg_imm
(arm_inst_ptr inst, int opc, int dreg,
int sreg, int imm, int saveWork, int execute_prefix)

1
jit/jit-gen-arm.h

@ -376,6 +376,7 @@ extern arm_inst_ptr _arm_alu_reg_imm
} while (0)
extern arm_inst_ptr _arm_mov_reg_imm
(arm_inst_ptr inst, int reg, int value, int execute_prefix);
extern int arm_is_complex_imm(int value);
#define arm_mov_reg_imm(inst,reg,imm) \
do { \
int __imm = (int)(imm); \

385
jit/jit-rules-arm.c

@ -47,6 +47,324 @@ void _jit_gen_get_elf_info(jit_elf_info_t *info)
info->abi_version = 0;
}
/*
* Flush the contents of the constant pool.
*/
#define check_for_word() \
do { \
if(inst >= limit) \
{ \
jit_cache_mark_full(&(gen->posn)); \
gen->num_constants = 0; \
gen->align_constants = 0; \
gen->first_constant_use = 0; \
return; \
} \
} while (0)
static void flush_constants(jit_gencode_t gen, int after_epilog)
{
arm_inst_ptr inst;
arm_inst_ptr limit;
arm_inst_ptr patch;
arm_inst_ptr current;
arm_inst_ptr fixup;
int index, value, offset;
/* Bail out if there are no constants to flush */
if(!(gen->num_constants))
{
return;
}
/* Initialize the cache output pointer */
inst = (arm_inst_ptr)(gen->posn.ptr);
limit = (arm_inst_ptr)(gen->posn.limit);
/* Jump over the constant pool if it is being output inline */
if(!after_epilog)
{
patch = inst;
check_for_word();
arm_jump_imm(inst, 0);
}
else
{
patch = 0;
}
/* Align the constant pool, if requested */
if(gen->align_constants && (((int)inst) & 7) != 0)
{
check_for_word();
*inst++ = 0;
}
/* Output the constant values and apply the necessary fixups */
for(index = 0; index < gen->num_constants; ++index)
{
current = inst;
check_for_word();
*inst++ = gen->constants[index];
fixup = gen->fixup_constants[index];
while(fixup != 0)
{
if((*fixup & 0x0F000000) == 0x05000000)
{
/* Word constant fixup */
value = *fixup & 0x0FFF;
offset = ((inst - 1 - fixup) * 4) - 8;
*fixup = ((*fixup & ~0x0FFF) | offset);
}
else
{
/* Floating-point constant fixup */
value = (*fixup & 0x00FF) * 4;
offset = ((inst - 1 - fixup) * 4) - 8;
*fixup = ((*fixup & ~0x00FF) | (offset / 4));
}
if(value)
{
fixup -= value;
}
else
{
fixup = 0;
}
}
}
/* Backpatch the jump if necessary */
if(!after_epilog)
{
arm_patch(patch, inst);
}
/* Flush the pool state and restart */
gen->num_constants = 0;
gen->align_constants = 0;
gen->first_constant_use = 0;
}
/*
* Perform a constant pool flush if we are too far from the starting point.
*/
static int flush_if_too_far(jit_gencode_t gen)
{
if(gen->first_constant_use &&
(((arm_inst_ptr)(gen->posn.ptr)) -
((arm_inst_ptr)(gen->first_constant_use))) >= 100)
{
flush_constants(gen, 0);
return 1;
}
else
{
return 0;
}
}
/*
* Add a fixup for a particular constant pool entry.
*/
static void add_constant_fixup
(jit_gencode_t gen, int index, arm_inst_ptr fixup)
{
arm_inst_ptr prev;
int value;
prev = gen->fixup_constants[index];
if(prev)
{
value = fixup - prev;
}
else
{
value = 0;
}
if((*fixup & 0x0F000000) == 0x05000000)
{
*fixup = ((*fixup & ~0x0FFF) | value);
}
else
{
*fixup = ((*fixup & ~0x00FF) | (value / 4));
}
gen->fixup_constants[index] = fixup;
if(!(gen->first_constant_use))
{
gen->first_constant_use = fixup;
}
}
/*
* Add an immediate value to the constant pool. The constant
* is loaded from the instruction at "fixup".
*/
static void add_constant(jit_gencode_t gen, int value, arm_inst_ptr fixup)
{
int index;
/* Search the constant pool for an existing copy of the value */
for(index = 0; index < gen->num_constants; ++index)
{
if(gen->constants[index] == value)
{
add_constant_fixup(gen, index, fixup);
return;
}
}
/* Flush the constant pool if there is insufficient space */
if(gen->num_constants >= JIT_ARM_MAX_CONSTANTS)
{
flush_constants(gen, 0);
}
/* Add the constant value to the pool */
gen->constants[gen->num_constants] = value;
gen->fixup_constants[gen->num_constants] = 0;
++(gen->num_constants);
add_constant_fixup(gen, gen->num_constants - 1, fixup);
}
/*
* Add a double-word immedite value to the constant pool.
*/
static void add_constant_dword
(jit_gencode_t gen, int value1, int value2, arm_inst_ptr fixup, int align)
{
int index;
/* Make sure that the constant pool is properly aligned when output */
if(align)
{
gen->align_constants = 1;
}
/* Search the constant pool for an existing copy of the value */
for(index = 0; index < (gen->num_constants - 1); ++index)
{
if(gen->constants[index] == value1 &&
gen->constants[index + 1] == value2)
{
if(!align || (index % 2) == 0)
{
add_constant_fixup(gen, index, fixup);
return;
}
}
}
/* Flush the constant pool if there is insufficient space */
if(gen->num_constants >= (JIT_ARM_MAX_CONSTANTS - 1))
{
flush_constants(gen, 0);
}
/* Align the constant pool on a 64-bit boundary if necessary */
if(align && (gen->num_constants % 2) != 0)
{
gen->constants[gen->num_constants] = 0;
gen->fixup_constants[gen->num_constants] = 0;
++(gen->num_constants);
}
/* Add the double word constant value to the pool */
gen->constants[gen->num_constants] = value1;
gen->fixup_constants[gen->num_constants] = 0;
gen->constants[gen->num_constants] = value2;
gen->fixup_constants[gen->num_constants] = 0;
gen->num_constants += 2;
add_constant_fixup(gen, gen->num_constants - 2, fixup);
}
/*
* Load an immediate value into a word register. If the value is
* complicated, then add an entry to the constant pool.
*/
static arm_inst_ptr mov_reg_imm
(jit_gencode_t gen, arm_inst_ptr inst, int reg, int value)
{
arm_inst_ptr fixup;
/* Bail out if the buffer is full */
if(inst >= (arm_inst_ptr)(gen->posn.limit))
{
return inst;
}
/* Bail out if the value is not complex enough to need a pool entry */
if(!arm_is_complex_imm(value))
{
arm_mov_reg_imm(inst, reg, value);
return inst;
}
/* Output a placeholder to load the value later */
fixup = inst;
arm_load_membase(inst, reg, ARM_PC, 0);
/* Add the constant to the pool, which may cause a flush */
gen->posn.ptr = (unsigned char *)inst;
add_constant(gen, value, fixup);
/* Return the new program counter location */
return (arm_inst_ptr)(gen->posn.ptr);
}
/*
* Load a float32 immediate value into a float register. If the value is
* complicated, then add an entry to the constant pool.
*/
static arm_inst_ptr mov_freg_imm_32
(jit_gencode_t gen, arm_inst_ptr inst, int reg, int value)
{
arm_inst_ptr fixup;
/* Bail out if the buffer is full */
if(inst >= (arm_inst_ptr)(gen->posn.limit))
{
return inst;
}
/* Output a placeholder to load the value later */
fixup = inst;
arm_load_membase_float32(inst, reg, ARM_PC, 0);
/* Add the constant to the pool, which may cause a flush */
gen->posn.ptr = (unsigned char *)inst;
add_constant(gen, value, fixup);
/* Return the new program counter location */
return (arm_inst_ptr)(gen->posn.ptr);
}
/*
* Load a float64 immediate value into a float register. If the value is
* complicated, then add an entry to the constant pool.
*/
static arm_inst_ptr mov_freg_imm_64
(jit_gencode_t gen, arm_inst_ptr inst, int reg, int value1, int value2)
{
arm_inst_ptr fixup;
/* Bail out if the buffer is full */
if(inst >= (arm_inst_ptr)(gen->posn.limit))
{
return inst;
}
/* Output a placeholder to load the value later */
fixup = inst;
arm_load_membase_float64(inst, reg, ARM_PC, 0);
/* Add the constant to the pool, which may cause a flush */
gen->posn.ptr = (unsigned char *)inst;
add_constant_dword(gen, value1, value2, fixup, 1);
/* Return the new program counter location */
return (arm_inst_ptr)(gen->posn.ptr);
}
/*
* Force values out of parameter registers that cannot be easily
* accessed in register form (i.e. long, float, and struct values).
@ -539,6 +857,9 @@ void _jit_gen_epilog(jit_gencode_t gen, jit_function_t func)
inst = (arm_inst_ptr)(gen->posn.ptr);
arm_pop_frame(inst, regset);
gen->posn.ptr = (unsigned char *)inst;
/* Flush the remainder of the constant pool */
flush_constants(gen, 1);
}
void *_jit_gen_redirector(jit_gencode_t gen, jit_function_t func)
@ -579,7 +900,11 @@ void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
int offset;
/* Make sure that we have sufficient space */
jit_cache_setup_output(20);
jit_cache_setup_output(32);
if(flush_if_too_far(gen))
{
inst = (arm_inst_ptr)(gen->posn.ptr);
}
/* Output an appropriate instruction to spill the value */
if(value->has_global_register)
@ -627,7 +952,11 @@ void _jit_gen_load_value
int offset;
/* Make sure that we have sufficient space */
jit_cache_setup_output(16);
jit_cache_setup_output(32);
if(flush_if_too_far(gen))
{
inst = (arm_inst_ptr)(gen->posn.ptr);
}
if(value->is_constant)
{
@ -641,8 +970,8 @@ void _jit_gen_load_value
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
{
arm_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg,
(jit_nint)(value->address));
inst = mov_reg_imm(gen, inst, _jit_reg_info[reg].cpu_reg,
(jit_nint)(value->address));
}
break;
@ -651,10 +980,10 @@ void _jit_gen_load_value
{
jit_long long_value;
long_value = jit_value_get_long_constant(value);
arm_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg,
(jit_int)long_value);
arm_mov_reg_imm(inst, _jit_reg_info[other_reg].cpu_reg,
(jit_int)(long_value >> 32));
inst = mov_reg_imm(gen, inst, _jit_reg_info[reg].cpu_reg,
(jit_int)long_value);
inst = mov_reg_imm(gen, inst, _jit_reg_info[other_reg].cpu_reg,
(jit_int)(long_value >> 32));
}
break;
@ -669,15 +998,14 @@ void _jit_gen_load_value
}
if(reg < 16)
{
arm_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg,
*((int *)&float32_value));
inst = mov_reg_imm(gen, inst, _jit_reg_info[reg].cpu_reg,
*((int *)&float32_value));
}
else
{
arm_load_membase_float32
(inst, _jit_reg_info[reg].cpu_reg, ARM_PC, 0);
arm_jump_imm(inst, 0);
*(inst)++ = *((int *)&float32_value);
inst = mov_freg_imm_32
(gen, inst, _jit_reg_info[reg].cpu_reg,
*((int *)&float32_value));
}
}
break;
@ -694,27 +1022,19 @@ void _jit_gen_load_value
}
if(reg < 16)
{
arm_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg,
((int *)&float64_value)[0]);
arm_mov_reg_imm(inst, _jit_reg_info[other_reg].cpu_reg,
((int *)&float64_value)[1]);
}
else if((((int)inst) & 7) == 0)
{
arm_load_membase_float64
(inst, _jit_reg_info[reg].cpu_reg, ARM_PC, 0);
arm_jump_imm(inst, 4);
*(inst)++ = ((int *)&float64_value)[0];
*(inst)++ = ((int *)&float64_value)[1];
inst = mov_reg_imm
(gen, inst, _jit_reg_info[reg].cpu_reg,
((int *)&float64_value)[0]);
inst = mov_reg_imm
(gen, inst, _jit_reg_info[other_reg].cpu_reg,
((int *)&float64_value)[1]);
}
else
{
arm_load_membase_float64
(inst, _jit_reg_info[reg].cpu_reg, ARM_PC, 4);
arm_jump_imm(inst, 8);
*(inst)++ = 0;
*(inst)++ = ((int *)&float64_value)[0];
*(inst)++ = ((int *)&float64_value)[1];
inst = mov_freg_imm_64
(gen, inst, _jit_reg_info[reg].cpu_reg,
((int *)&float64_value)[0],
((int *)&float64_value)[1]);
}
}
break;
@ -944,6 +1264,7 @@ static arm_inst_ptr jump_to_epilog
void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
jit_block_t block, jit_insn_t insn)
{
flush_if_too_far(gen);
switch(insn->opcode)
{
#define JIT_INCLUDE_RULES

18
jit/jit-rules-arm.h

@ -96,6 +96,24 @@ extern "C" {
*/
#define JIT_ALIGN_OVERRIDES 0
/*
* Extra state information that is added to the "jit_gencode" structure.
*/
#define JIT_ARM_MAX_CONSTANTS 32
#define jit_extra_gen_state \
int constants[JIT_ARM_MAX_CONSTANTS]; \
int *fixup_constants[JIT_ARM_MAX_CONSTANTS]; \
int num_constants; \
int align_constants; \
int *first_constant_use
#define jit_extra_gen_init(gen) \
do { \
(gen)->num_constants = 0; \
(gen)->align_constants = 0; \
(gen)->first_constant_use = 0; \
} while (0)
#define jit_extra_gen_cleanup(gen) do { ; } while (0)
#ifdef __cplusplus
};
#endif

59
jit/jit-rules-arm.sel

@ -74,7 +74,7 @@ JIT_OP_IMUL: binary
{
case 0:
{
arm_mov_reg_imm(inst, $1, 0);
arm_mov_reg_imm8(inst, $1, 0);
}
break;
@ -596,10 +596,10 @@ JIT_OP_RETURN_LONG: spill_before
[] -> {
if(jit_value_is_constant(insn->value1))
{
arm_mov_reg_imm(inst, ARM_R0,
((jit_int *)(insn->value1->address))[0]);
arm_mov_reg_imm(inst, ARM_R1,
((jit_int *)(insn->value1->address))[1]);
inst = mov_reg_imm
(gen, inst, ARM_R0, ((jit_int *)(insn->value1->address))[0]);
inst = mov_reg_imm
(gen, inst, ARM_R1, ((jit_int *)(insn->value1->address))[1]);
}
else
{
@ -634,7 +634,8 @@ JIT_OP_RETURN_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual
}
if(insn->value1->is_constant)
{
arm_mov_reg_imm(inst, ARM_R0, ((int *)(insn->value1->address))[0]);
inst = mov_reg_imm
(gen, inst, ARM_R0, ((int *)(insn->value1->address))[0]);
}
else
{
@ -667,8 +668,10 @@ JIT_OP_RETURN_FLOAT64, JIT_OP_RETURN_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual
}
if(insn->value1->is_constant)
{
arm_mov_reg_imm(inst, ARM_R0, ((int *)(insn->value1->address))[0]);
arm_mov_reg_imm(inst, ARM_R1, ((int *)(insn->value1->address))[1]);
inst = mov_reg_imm
(gen, inst, ARM_R0, ((int *)(insn->value1->address))[0]);
inst= mov_reg_imm
(gen, inst, ARM_R1, ((int *)(insn->value1->address))[1]);
}
else
{
@ -836,12 +839,12 @@ JIT_OP_COPY_LONG: manual
}
if(insn->value1->is_constant)
{
arm_mov_reg_imm(inst, ARM_WORK,
((int *)(insn->value1->address))[0]);
inst = mov_reg_imm
(gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
arm_store_membase(inst, ARM_WORK, ARM_FP,
insn->dest->frame_offset);
arm_mov_reg_imm(inst, ARM_WORK,
((int *)(insn->value1->address))[1]);
inst = mov_reg_imm
(gen, inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
arm_store_membase(inst, ARM_WORK, ARM_FP,
insn->dest->frame_offset + 4);
}
@ -877,8 +880,8 @@ JIT_OP_COPY_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual
}
if(insn->value1->is_constant)
{
arm_mov_reg_imm(inst, ARM_WORK,
((int *)(insn->value1->address))[0]);
inst = mov_reg_imm
(gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
}
else
{
@ -907,12 +910,12 @@ JIT_OP_COPY_FLOAT64, JIT_OP_COPY_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual
}
if(insn->value1->is_constant)
{
arm_mov_reg_imm(inst, ARM_WORK,
((int *)(insn->value1->address))[0]);
inst = mov_reg_imm
(gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
arm_store_membase(inst, ARM_WORK, ARM_FP,
insn->dest->frame_offset);
arm_mov_reg_imm(inst, ARM_WORK,
((int *)(insn->value1->address))[1]);
inst = mov_reg_imm
(gen, inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
arm_store_membase(inst, ARM_WORK, ARM_FP,
insn->dest->frame_offset + 4);
}
@ -1034,11 +1037,11 @@ JIT_OP_PUSH_LONG: manual
}
if(insn->value1->is_constant)
{
arm_mov_reg_imm(inst, ARM_WORK,
((int *)(insn->value1->address))[1]);
inst = mov_reg_imm
(gen, inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
arm_push_reg(inst, ARM_WORK);
arm_mov_reg_imm(inst, ARM_WORK,
((int *)(insn->value1->address))[0]);
inst = mov_reg_imm
(gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
arm_push_reg(inst, ARM_WORK);
}
else
@ -1071,8 +1074,8 @@ JIT_OP_PUSH_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual
}
if(insn->value1->is_constant)
{
arm_mov_reg_imm(inst, ARM_WORK,
((int *)(insn->value1->address))[0]);
inst = mov_reg_imm
(gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
}
else
{
@ -1101,11 +1104,11 @@ JIT_OP_PUSH_FLOAT64, JIT_OP_PUSH_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual
}
if(insn->value1->is_constant)
{
arm_mov_reg_imm(inst, ARM_WORK,
((int *)(insn->value1->address))[1]);
inst = mov_reg_imm
(gen, inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
arm_push_reg(inst, ARM_WORK);
arm_mov_reg_imm(inst, ARM_WORK,
((int *)(insn->value1->address))[0]);
inst = mov_reg_imm
(gen, inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
arm_push_reg(inst, ARM_WORK);
}
else

Loading…
Cancel
Save