#include "jit-internal.h"
#include "jit-rules.h"
#include "jit-apply-rules.h"
#if defined(JIT_BACKEND_ARM)
#include "jit-gen-arm.h"
#include "jit-reg-alloc.h"
#include "jit-setjmp.h"
#include <stdio.h>
#include <stdlib.h>
#define ARM_REG_R0 0
#define ARM_REG_R1 1
#define ARM_REG_R2 2
#define ARM_REG_R3 3
#define ARM_REG_R4 4
#define ARM_REG_R5 5
#define ARM_REG_R6 6
#define ARM_REG_R7 7
#define ARM_REG_R8 8
#define ARM_REG_R9 9
#define ARM_REG_R10 10
#define ARM_REG_FP 11
#define ARM_REG_R12 12
#define ARM_REG_SP 13
#define ARM_REG_LR 14
#define ARM_REG_PC 15
#ifdef JIT_ARM_HAS_FPA
#define ARM_F0 16
#define ARM_F1 17
#define ARM_F2 18
#define ARM_F3 19
#define ARM_F4 20
#define ARM_F5 21
#define ARM_F6 22
#define ARM_F7 23
#endif
#ifdef JIT_ARM_HAS_VFP
#define ARM_REG_S0 16
#define ARM_REG_S1 17
#define ARM_REG_S2 18
#define ARM_REG_S3 19
#define ARM_REG_S4 20
#define ARM_REG_S5 21
#define ARM_REG_S6 22
#define ARM_REG_S7 23
#define ARM_REG_S8 24
#define ARM_REG_S9 25
#define ARM_REG_S10 26
#define ARM_REG_S11 27
#define ARM_REG_S12 28
#define ARM_REG_S13 29
#define ARM_REG_S14 30
#define ARM_REG_S15 31
#define ARM_REG_D8 32
#define ARM_REG_D9 33
#define ARM_REG_D10 34
#define ARM_REG_D11 35
#define ARM_REG_D12 36
#define ARM_REG_D13 37
#define ARM_REG_D14 38
#define ARM_REG_D15 39
#endif
#define IS_WORD_REG(reg) ((reg) <= ARM_REG_PC)
#define IS_FLOAT_REG(reg) ((reg) > ARM_REG_PC)
#define ROUND_STACK(size) \
(((size) + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1))
#define jit_reg_current_other_reg(gen,reg) \
(gen->contents[reg].is_long_start ? jit_reg_other_reg(reg) : -1)
static _jit_regclass_t *arm_reg;
static _jit_regclass_t *arm_freg;
static _jit_regclass_t *arm_freg32;
static _jit_regclass_t *arm_freg64;
static _jit_regclass_t *arm_lreg;
#define jit_gen_load_inst_ptr(gen,inst) \
do { \
arm_inst_buf_init((inst), (gen)->ptr, (gen)->limit); \
} while (0)
#define jit_gen_save_inst_ptr(gen,inst) \
do { \
(gen)->ptr = (unsigned char *)arm_inst_get_posn(inst); \
} while (0)
static int get_temp_reg(int reg1, int reg2, int reg3)
{
if(reg1 != ARM_R5 && reg2 != ARM_R5 && reg3 != ARM_R5)
{
return ARM_R5;
}
if(reg1 != ARM_R6 && reg2 != ARM_R6 && reg3 != ARM_R6)
{
return ARM_R6;
}
if(reg1 != ARM_R7 && reg2 != ARM_R7 && reg3 != ARM_R7)
{
return ARM_R7;
}
if(reg1 != ARM_R8 && reg2 != ARM_R8 && reg3 != ARM_R8)
{
return ARM_R8;
}
if(reg1 != ARM_R10 && reg2 != ARM_R10 && reg3 != ARM_R10)
{
return ARM_R10;
}
return ARM_R12;
}
static void mov_reg_imm (jit_gencode_t gen, arm_inst_buf *inst, int reg, int value);
static arm_inst_buf memory_copy (jit_gencode_t gen, arm_inst_buf inst, int dreg, jit_nint doffset, int sreg, jit_nint soffset, jit_nuint size, int temp_reg)
{
if(temp_reg == -1)
{
temp_reg = get_temp_reg(dreg, sreg, -1);
}
if(size <= 4 * sizeof(void *))
{
int offset = 0;
while(size >= sizeof(void *))
{
arm_mov_reg_membase(inst, temp_reg, sreg, soffset + offset, sizeof(void *));
arm_mov_membase_reg(inst, dreg, doffset + offset, temp_reg, sizeof(void *));
size -= sizeof(void *);
offset += sizeof(void *);
}
if(size >= 2)
{
arm_mov_reg_membase(inst, temp_reg, sreg, soffset + offset, 2);
arm_mov_membase_reg(inst, dreg, doffset + offset, temp_reg, 2);
size -= 2;
offset += 2;
}
if(size >= 1)
{
arm_mov_reg_membase(inst, temp_reg, sreg, soffset + offset, 1);
arm_mov_membase_reg(inst, dreg, doffset + offset, temp_reg, 1);
}
}
else
{
mov_reg_imm(gen, &inst, ARM_R2, size);
if(soffset == 0)
{
arm_mov_reg_reg(inst, ARM_R1, sreg);
}
else
{
arm_alu_reg_imm(inst, ARM_ADD, temp_reg, sreg, soffset);
arm_mov_reg_reg(inst, ARM_R1, temp_reg);
}
if(doffset == 0)
{
arm_mov_reg_reg(inst, ARM_R0, dreg);
}
else
{
arm_alu_reg_imm(inst, ARM_ADD, temp_reg, dreg, doffset);
arm_mov_reg_reg(inst, ARM_R0, temp_reg);
}
arm_call(inst, jit_memcpy);
}
return inst;
}
static void flush_constants(jit_gencode_t gen, int after_epilog)
{
arm_inst_buf inst;
arm_inst_word *patch;
arm_inst_word *current;
arm_inst_word *fixup;
int index, value, offset;
if(!(gen->num_constants))
{
return;
}
jit_gen_load_inst_ptr(gen, inst);
if(!after_epilog)
{
patch = arm_inst_get_posn(inst);
arm_jump_imm(inst, 0);
}
else
{
patch = 0;
}
if(gen->align_constants && (((int)arm_inst_get_posn(inst)) & 7) != 0)
{
arm_inst_add(inst, 0);
}
for(index = 0; index < gen->num_constants; ++index)
{
current = arm_inst_get_posn(inst);
arm_inst_add(inst, gen->constants[index]);
fixup = gen->fixup_constants[index];
while(fixup != 0)
{
if((*fixup & 0x0F000000) == 0x05000000)
{
value = *fixup & 0x0FFF;
offset = ((arm_inst_get_posn(inst) - 1 - fixup) * 4) - 8;
*fixup = ((*fixup & ~0x0FFF) | offset);
}
else
{
value = (*fixup & 0x00FF) * 4;
offset = ((arm_inst_get_posn(inst) - 1 - fixup) * 4) - 8;
*fixup = ((*fixup & ~0x00FF) | (offset / 4));
}
if(value)
{
fixup -= value / sizeof(void *);
}
else
{
fixup = 0;
}
}
}
if(!after_epilog)
{
arm_patch(inst, patch, arm_inst_get_posn(inst));
}
gen->num_constants = 0;
gen->align_constants = 0;
gen->first_constant_use = 0;
jit_gen_save_inst_ptr(gen, inst);
}
static int flush_if_too_far(jit_gencode_t gen)
{
if(gen->first_constant_use &&
(((arm_inst_word *)(gen->ptr)) -
((arm_inst_word *)(gen->first_constant_use))) >= 100)
{
flush_constants(gen, 0);
return 1;
}
else
{
return 0;
}
}
static void add_constant_fixup
(jit_gencode_t gen, int index, arm_inst_word *fixup)
{
arm_inst_word *prev;
int value;
if(((unsigned char *)fixup) >= gen->limit)
{
return;
}
prev = gen->fixup_constants[index];
if(prev)
{
value = (fixup - prev) * sizeof(void *);
}
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;
}
}
static void add_constant(jit_gencode_t gen, int value, arm_inst_word *fixup)
{
int index;
for(index = 0; index < gen->num_constants; ++index)
{
if(gen->constants[index] == value)
{
add_constant_fixup(gen, index, fixup);
return;
}
}
if(gen->num_constants >= JIT_ARM_MAX_CONSTANTS)
{
flush_constants(gen, 0);
}
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);
}
static void add_constant_dword
(jit_gencode_t gen, int value1, int value2, arm_inst_word *fixup, int align)
{
int index;
if(align)
{
gen->align_constants = 1;
}
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;
}
}
}
if(gen->num_constants >= (JIT_ARM_MAX_CONSTANTS - 1))
{
flush_constants(gen, 0);
}
if(align && (gen->num_constants % 2) != 0)
{
gen->constants[gen->num_constants] = 0;
gen->fixup_constants[gen->num_constants] = 0;
++(gen->num_constants);
}
gen->constants[gen->num_constants] = value1;
gen->fixup_constants[gen->num_constants] = 0;
gen->constants[gen->num_constants+1] = value2;
gen->fixup_constants[gen->num_constants+1] = 0;
gen->num_constants += 2;
add_constant_fixup(gen, gen->num_constants - 2, fixup);
}
static void mov_reg_imm
(jit_gencode_t gen, arm_inst_buf *inst, int reg, int value)
{
arm_inst_word *fixup;
if(!arm_is_complex_imm(value))
{
arm_mov_reg_imm(*inst, reg, value);
return;
}
fixup = arm_inst_get_posn(*inst);
arm_load_membase(*inst, reg, ARM_PC, 0);
jit_gen_save_inst_ptr(gen, *inst);
add_constant(gen, value, fixup);
jit_gen_load_inst_ptr(gen, *inst);
}
static void mov_freg_imm_32
(jit_gencode_t gen, arm_inst_buf *inst, int reg, int value)
{
arm_inst_word *fixup;
fixup = arm_inst_get_posn(*inst);
arm_load_membase_float32(*inst, reg, ARM_PC, 0);
jit_gen_save_inst_ptr(gen, *inst);
add_constant(gen, value, fixup);
jit_gen_load_inst_ptr(gen, *inst);
}
static void mov_freg_imm_64
(jit_gencode_t gen, arm_inst_buf *inst, int reg, int value1, int value2)
{
arm_inst_word *fixup;
fixup = arm_inst_get_posn(*inst);
arm_load_membase_float64(*inst, reg, ARM_PC, 0);
jit_gen_save_inst_ptr(gen, *inst);
add_constant_dword(gen, value1, value2, fixup, 1);
jit_gen_load_inst_ptr(gen, *inst);
}
static void output_branch
(jit_function_t func, arm_inst_buf *inst, int cond, jit_insn_t insn)
{
jit_block_t block;
int offset;
if((insn->flags & JIT_INSN_VALUE1_IS_LABEL) != 0)
{
block = jit_block_from_label(func, (jit_label_t)(insn->value1));
}
else
{
block = jit_block_from_label(func, (jit_label_t)(insn->dest));
}
if(!block)
{
return;
}
if(arm_inst_get_posn(*inst) >= arm_inst_get_limit(*inst))
{
return;
}
if(block->address)
{
arm_branch(*inst, cond, block->address);
}
else
{
if(block->fixup_list)
{
offset = (int)(((unsigned char *)arm_inst_get_posn(*inst)) -
((unsigned char *)(block->fixup_list)));
}
else
{
offset = 0;
}
arm_branch_imm(*inst, cond, offset);
block->fixup_list = (void *)(arm_inst_get_posn(*inst) - 1);
}
}
static void throw_builtin
(arm_inst_buf *inst, jit_function_t func, int cond, int type)
{
arm_inst_word *patch;
patch = arm_inst_get_posn(*inst);
arm_branch_imm(*inst, cond ^ 0x01, 0);
if(func->builder->setjmp_value != 0)
{
_jit_gen_fix_value(func->builder->setjmp_value);
arm_mov_reg_reg(*inst, ARM_WORK, ARM_PC);
arm_store_membase(*inst, ARM_WORK, ARM_FP,
func->builder->setjmp_value->frame_offset +
jit_jmp_catch_pc_offset);
}
arm_mov_reg_imm(*inst, ARM_WORK, type);
arm_push_reg(*inst, ARM_WORK);
arm_call(*inst, jit_exception_builtin);
arm_patch(*inst, patch, arm_inst_get_posn(*inst));
}
static void jump_to_epilog
(jit_gencode_t gen, arm_inst_buf *inst, jit_block_t block)
{
int offset;
if(_jit_block_is_final(block))
{
return;
}
if(arm_inst_get_posn(*inst) >= arm_inst_get_limit(*inst))
{
return;
}
if(gen->epilog_fixup)
{
offset = (int)(((unsigned char *)arm_inst_get_posn(*inst)) -
((unsigned char *)(gen->epilog_fixup)));
}
else
{
offset = 0;
}
arm_branch_imm(*inst, ARM_CC_AL, offset);
gen->epilog_fixup = (void *)(arm_inst_get_posn(*inst) - 1);
}
#define TODO() \
do { \
fprintf(stderr, "TODO at %s, %d\n", __FILE__, (int)__LINE__); \
} while (0)
void _jit_init_backend(void)
{
arm_reg = _jit_regclass_create(
"reg", JIT_REG_WORD, 9,
ARM_REG_R0, ARM_REG_R1,
ARM_REG_R2, ARM_REG_R3,
ARM_REG_R4, ARM_REG_R5,
ARM_REG_R6, ARM_REG_R7,
ARM_REG_R8);
#ifdef JIT_ARM_HAS_FPA
arm_freg = _jit_regclass_create(
"freg64", JIT_REG_ARM_FLOAT, 4,
ARM_REG_F0, ARM_REG_F1,
ARM_REG_F2, ARM_REG_F3,
);
#endif
#ifdef JIT_ARM_HAS_VFP
arm_freg32 = _jit_regclass_create(
"freg32", JIT_REG_ARM_FLOAT32, 16,
ARM_REG_S0, ARM_REG_S1,
ARM_REG_S2, ARM_REG_S3,
ARM_REG_S4, ARM_REG_S5,
ARM_REG_S6, ARM_REG_S7,
ARM_REG_S8, ARM_REG_S9,
ARM_REG_S10, ARM_REG_S11,
ARM_REG_S12, ARM_REG_S13,
ARM_REG_S14, ARM_REG_S15);
arm_freg64 = _jit_regclass_create(
"freg64", JIT_REG_ARM_FLOAT64, 8,
ARM_REG_D8, ARM_REG_D9,
ARM_REG_D10, ARM_REG_D11,
ARM_REG_D12, ARM_REG_D13,
ARM_REG_D14, ARM_REG_D15);
#endif
arm_lreg = _jit_regclass_create(
"lreg", JIT_REG_LONG, 2,
ARM_REG_R0, ARM_REG_R2);
}
void _jit_gen_get_elf_info(jit_elf_info_t *info)
{
info->machine = 40;
info->abi = 0;
info->abi_version = 0;
}
int _jit_setup_indirect_pointer(jit_function_t func, jit_value_t value)
{
return jit_insn_outgoing_reg(func, value, ARM_WORK);
}
int _jit_create_call_return_insns
(jit_function_t func, jit_type_t signature,
jit_value_t *args, unsigned int num_args,
jit_value_t return_value, int is_nested)
{
jit_type_t return_type;
int ptr_return;
return_type = jit_type_normalize(jit_type_get_return(signature));
ptr_return = jit_type_return_via_pointer(return_type);
if(!return_value || ptr_return)
{
return 1;
}
if(jit_type_is_struct(return_type) || jit_type_is_union(return_type))
{
if(!jit_insn_flush_struct(func, return_value))
{
return 0;
}
}
else if(return_type->kind != JIT_TYPE_VOID)
{
if(!jit_insn_return_reg(func, return_value, ARM_REG_R0))
{
return 0;
}
}
return 1;
}
int _jit_opcode_is_supported(int opcode)
{
switch(opcode)
{
#define JIT_INCLUDE_SUPPORTED
#include "jit-rules-arm.inc"
#undef JIT_INCLUDE_SUPPORTED
}
return 0;
}
void *_jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf)
{
unsigned int prolog[JIT_PROLOG_SIZE / sizeof(int)];
arm_inst_buf inst;
int reg, regset;
unsigned int saved;
unsigned int frame_size;
unsigned int stack_growth;
arm_inst_buf_init(inst, prolog, prolog + JIT_PROLOG_SIZE / sizeof(int));
regset = 0;
saved = 0;
for(reg = 0; reg <= 15; ++reg)
{
if(jit_reg_is_used(gen->touched, reg) &&
(_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
{
regset |= (1 << reg);
saved += sizeof(void *);
}
}
arm_setup_frame(inst, regset);
stack_growth=(saved + 4 * sizeof(void *));
frame_size = func->builder->frame_size - stack_growth;
frame_size = func->builder->frame_size - (saved + 3 * sizeof(void *));
frame_size += (unsigned int)(func->builder->param_area_size);
while(frame_size % JIT_SP_ALIGN_PUBLIC != 0)
{
frame_size++;
}
if (stack_growth % JIT_SP_ALIGN_PUBLIC != 0)
{
frame_size += (stack_growth % JIT_SP_ALIGN_PUBLIC);
}
if(frame_size > 0)
{
arm_alu_reg_imm(inst, ARM_SUB, ARM_SP, ARM_SP, frame_size);
}
reg = (int)((arm_inst_get_posn(inst) - prolog) * sizeof(unsigned int));
jit_memcpy(((unsigned char *)buf) + JIT_PROLOG_SIZE - reg, prolog, reg);
return (void *)(((unsigned char *)buf) + JIT_PROLOG_SIZE - reg);
}
void _jit_gen_epilog(jit_gencode_t gen, jit_function_t func)
{
int reg, regset;
arm_inst_buf inst;
void **fixup;
void **next;
jit_nint offset;
jit_gen_load_inst_ptr(gen, inst);
regset = 0;
for(reg = 0; reg <= 15; ++reg)
{
if(jit_reg_is_used(gen->touched, reg) &&
(_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
{
regset |= (1 << reg);
}
}
fixup = (void **)(gen->epilog_fixup);
while(fixup != 0)
{
offset = (((jit_nint)(fixup[0])) & 0x00FFFFFF) << 2;
if(!offset)
{
next = 0;
}
else
{
next = (void **)(((unsigned char *)fixup) - offset);
}
arm_patch(inst, fixup, arm_inst_get_posn(inst));
fixup = next;
}
gen->epilog_fixup = 0;
arm_pop_frame(inst, regset);
jit_gen_save_inst_ptr(gen, inst);
flush_constants(gen, 1);
}
#if 0#endif
#define jit_cache_setup_output(needed) \
arm_inst_buf inst; \
jit_gen_load_inst_ptr(gen, inst)
#define jit_cache_end_output() \
jit_gen_save_inst_ptr(gen, inst)
void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
int other_reg, jit_value_t value)
{
int offset;
jit_cache_setup_output(32);
if(flush_if_too_far(gen))
{
jit_gen_load_inst_ptr(gen, inst);
}
if(value->has_global_register)
{
if (IS_FLOAT_REG(reg))
{
printf("TODO:Copy from float reg to global reg is not handled properly in %s\n", __FILE__);
abort();
}
else
{
arm_mov_reg_reg(inst, _jit_reg_info[value->global_reg].cpu_reg, _jit_reg_info[reg].cpu_reg);
}
}
else
{
_jit_gen_fix_value(value);
offset = (int)(value->frame_offset);
if(IS_WORD_REG(reg))
{
arm_store_membase(inst, reg, ARM_FP, offset);
if(other_reg != -1)
{
offset += sizeof(void *);
arm_store_membase(inst, other_reg, ARM_FP, offset);
}
}
else if(jit_type_normalize(value->type)->kind == JIT_TYPE_FLOAT32)
{
arm_store_membase_float32(inst, _jit_reg_info[value->reg].cpu_reg, ARM_FP, offset);
}
else
{
arm_store_membase_float64(inst, _jit_reg_info[value->reg].cpu_reg, ARM_FP, offset);
}
}
jit_cache_end_output();
}
void _jit_gen_free_reg(jit_gencode_t gen, int reg,
int other_reg, int value_used)
{
}
void _jit_gen_load_value
(jit_gencode_t gen, int reg, int other_reg, jit_value_t value)
{
int offset;
jit_cache_setup_output(32);
if(flush_if_too_far(gen))
{
jit_gen_load_inst_ptr(gen, inst);
}
if(value->is_constant)
{
switch(jit_type_normalize(value->type)->kind)
{
case JIT_TYPE_SBYTE:
case JIT_TYPE_UBYTE:
case JIT_TYPE_SHORT:
case JIT_TYPE_USHORT:
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
{
mov_reg_imm(gen, &inst, _jit_reg_info[reg].cpu_reg,
(jit_nint)(value->address));
}
break;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
{
jit_long long_value;
long_value = jit_value_get_long_constant(value);
mov_reg_imm(gen, &inst, _jit_reg_info[reg].cpu_reg,
(jit_int)long_value);
mov_reg_imm(gen, &inst, _jit_reg_info[reg].cpu_reg + 1,
(jit_int)(long_value >> 32));
}
break;
case JIT_TYPE_FLOAT32:
{
jit_float32 float32_value;
float32_value = jit_value_get_float32_constant(value);
if(IS_WORD_REG(reg))
{
mov_reg_imm(gen, &inst, _jit_reg_info[reg].cpu_reg,
*((int *)&float32_value));
}
else
{
mov_freg_imm_32
(gen, &inst, _jit_reg_info[reg].cpu_reg,
*((int *)&float32_value));
}
}
break;
case JIT_TYPE_FLOAT64:
case JIT_TYPE_NFLOAT:
{
jit_float64 float64_value;
float64_value = jit_value_get_float64_constant(value);
if(IS_WORD_REG(reg))
{
mov_reg_imm
(gen, &inst, _jit_reg_info[reg].cpu_reg,
((int *)&float64_value)[0]);
mov_reg_imm
(gen, &inst, _jit_reg_info[reg].cpu_reg + 1,
((int *)&float64_value)[1]);
}
else
{
mov_freg_imm_64
(gen, &inst, _jit_reg_info[reg].cpu_reg,
((int *)&float64_value)[0],
((int *)&float64_value)[1]);
}
}
break;
}
}
else if(value->in_global_register)
{
if(IS_FLOAT_REG(reg))
{
#ifdef JIT_ARM_HAS_VFP
if(jit_type_normalize(value->type)->kind == JIT_TYPE_FLOAT32)
{
arm_mov_float_reg(inst,
_jit_reg_info[reg].cpu_reg,
_jit_reg_info[value->global_reg].cpu_reg);
}
else
{
arm_mov_double_reg_reg(inst,
_jit_reg_info[reg].cpu_reg,
_jit_reg_info[value->global_reg].cpu_reg,
_jit_reg_info[value->global_reg].cpu_reg + 1);
}
#endif
#ifdef JIT_ARM_HAS_FPA
TODO();
abort();
#endif
}
else
{
arm_mov_reg_reg(inst,
_jit_reg_info[reg].cpu_reg,
_jit_reg_info[value->global_reg].cpu_reg);
}
}
else if(value->in_register)
{
switch(jit_type_normalize(value->type)->kind)
{
case JIT_TYPE_SBYTE:
case JIT_TYPE_UBYTE:
case JIT_TYPE_SHORT:
case JIT_TYPE_USHORT:
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
{
arm_mov_reg_reg(inst, jit_reg_code(reg), jit_reg_code(value->reg));
}
break;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
{
assert(jit_reg_code(other_reg) !=-1);
assert(jit_reg_other_reg(value->reg) != -1);
arm_mov_reg_reg(inst, jit_reg_code(reg), jit_reg_code(value->reg));
arm_mov_reg_reg(inst, jit_reg_code(other_reg), jit_reg_other_reg(value->reg));
}
break;
case JIT_TYPE_FLOAT32:
{
#ifdef JIT_ARM_HAS_VFP
if(IS_FLOAT_REG(reg))
{
if(IS_WORD_REG(value->reg))
{
arm_mov_float_reg(inst,
jit_reg_code(reg),
jit_reg_code(value->reg));
}
else
{
arm_alu_freg_32(inst, ARM_MVF,
jit_reg_code(reg),
jit_reg_code(value->reg));
}
}
else
{
if(IS_WORD_REG(value->reg))
{
arm_mov_reg_reg(inst,
jit_reg_code(reg),
jit_reg_code(value->reg));
}
else
{
arm_mov_reg_float(inst,
jit_reg_code(reg),
jit_reg_code(value->reg));
}
}
#endif
#ifdef JIT_ARM_HAS_FPA
TODO();
abort();
#endif
}
break;
case JIT_TYPE_FLOAT64:
case JIT_TYPE_NFLOAT:
{
#ifdef JIT_ARM_HAS_VFP
if(IS_FLOAT_REG(reg))
{
if(IS_WORD_REG(value->reg))
{
assert(jit_reg_other_reg(value->reg) != -1);
arm_mov_double_reg_reg(inst,
jit_reg_code(reg),
jit_reg_code(value->reg),
jit_reg_other_reg(value->reg));
}
else
{
arm_alu_freg(inst, ARM_MVF,
jit_reg_code(reg),
jit_reg_code(value->reg));
}
}
else
{
if(IS_WORD_REG(value->reg))
{
arm_mov_reg_reg(inst,
jit_reg_code(reg),
jit_reg_code(value->reg));
}
else
{
assert(jit_reg_other_reg(reg));
arm_mov_reg_reg_double(inst,
jit_reg_code(reg),
jit_reg_other_reg(reg),
jit_reg_code(value->reg));
}
}
#endif
#ifdef JIT_ARM_HAS_FPA
TODO();
abort();
#endif
}
break;
}
}
else
{
assert(!value->in_global_register && !value->is_constant && !value->in_register);
_jit_gen_fix_value(value);
offset = (int)(value->frame_offset);
switch(jit_type_normalize(value->type)->kind)
{
case JIT_TYPE_SBYTE:
{
arm_load_membase_sbyte(inst, _jit_reg_info[reg].cpu_reg,
ARM_FP, offset);
}
break;
case JIT_TYPE_UBYTE:
{
arm_load_membase_byte(inst, _jit_reg_info[reg].cpu_reg,
ARM_FP, offset);
}
break;
case JIT_TYPE_SHORT:
{
arm_load_membase_short(inst, _jit_reg_info[reg].cpu_reg,
ARM_FP, offset);
}
break;
case JIT_TYPE_USHORT:
{
arm_load_membase_ushort(inst, _jit_reg_info[reg].cpu_reg,
ARM_FP, offset);
}
break;
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
{
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
ARM_FP, offset);
}
break;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
{
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
ARM_FP, offset);
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg + 1,
ARM_FP, offset + 4);
}
break;
case JIT_TYPE_FLOAT32:
{
if(IS_WORD_REG(reg))
{
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
ARM_FP, offset);
}
else
{
arm_load_membase_float32
(inst, _jit_reg_info[reg].cpu_reg, ARM_FP, offset);
}
}
break;
case JIT_TYPE_FLOAT64:
case JIT_TYPE_NFLOAT:
{
if(IS_WORD_REG(reg))
{
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
ARM_FP, offset);
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg + 1,
ARM_FP, offset + 4);
}
else
{
arm_load_membase_float64
(inst, _jit_reg_info[reg].cpu_reg, ARM_FP, offset);
}
}
break;
}
}
jit_cache_end_output();
}
void _jit_gen_load_value_struct (jit_gencode_t gen, int reg, jit_value_t value)
{
int offset;
jit_cache_setup_output(32);
if(flush_if_too_far(gen))
{
jit_gen_load_inst_ptr(gen, inst);
}
if(value->is_constant)
{
TODO();
abort();
}
else if(value->has_global_register)
{
if (!value->in_global_register)
{
int reg = value->reg;
int other_reg = jit_reg_current_other_reg(gen,reg);
_jit_gen_spill_reg(gen, reg, other_reg, value);
value->in_global_register=1;
jit_gen_load_inst_ptr(gen, inst);
}
arm_mov_reg_reg(inst, _jit_reg_info[reg].cpu_reg,
_jit_reg_info[value->global_reg].cpu_reg);
}
else
{
_jit_gen_fix_value(value);
offset = (int)(value->frame_offset);
if(value->in_register)
{
int reg = value->reg;
int other_reg = jit_reg_current_other_reg(gen,reg);
_jit_gen_spill_reg(gen, reg, other_reg, value);
value->in_frame=1;
jit_gen_load_inst_ptr(gen, inst);
}
assert(jit_type_normalize(value->type)->kind==JIT_TYPE_STRUCT);
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg, ARM_FP, offset);
if (jit_type_get_size(jit_value_get_type(value)) > 4)
{
TODO();
abort();
}
}
jit_cache_end_output();
}
void _jit_gen_spill_global(jit_gencode_t gen, int reg, jit_value_t value)
{
}
void _jit_gen_load_global(jit_gencode_t gen, int reg, jit_value_t value)
{
jit_cache_setup_output(32);
arm_load_membase(inst, _jit_reg_info[value->global_reg].cpu_reg,
ARM_FP, value->frame_offset);
jit_cache_end_output();
}
void _jit_gen_fix_value(jit_value_t value)
{
if(!(value->has_frame_offset) && !(value->is_constant))
{
jit_nint size = (jit_nint)(ROUND_STACK(jit_type_get_size(value->type)));
value->block->func->builder->frame_size += size;
value->frame_offset = -(value->block->func->builder->frame_size);
value->has_frame_offset = 1;
}
}
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
#include "jit-rules-arm.inc"
#undef JIT_INCLUDE_RULES
default:
{
fprintf(stderr, "TODO(%x) at %s, %d\n",
(int)(insn->opcode), __FILE__, (int)__LINE__);
}
break;
}
}
void _jit_gen_start_block(jit_gencode_t gen, jit_block_t block)
{
void **fixup;
void **next;
jit_nint offset;
arm_inst_buf inst;
block->address = (void *)(gen->ptr);
fixup = (void **)(block->fixup_list);
while(fixup != 0)
{
offset = (((jit_nint)(fixup[0])) & 0x00FFFFFF) << 2;
if(!offset)
{
next = 0;
}
else
{
next = (void **)(((unsigned char *)fixup) - offset);
}
jit_gen_load_inst_ptr(gen, inst);
arm_patch(inst, fixup, block->address);
fixup = next;
}
block->fixup_list = 0;
}
void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
{
}
int _jit_gen_is_global_candidate(jit_type_t type)
{
switch(jit_type_remove_tags(type)->kind)
{
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
case JIT_TYPE_NINT:
case JIT_TYPE_NUINT:
case JIT_TYPE_PTR:
case JIT_TYPE_SIGNATURE: return 1;
}
return 0;
}
int
_jit_reg_get_pair(jit_type_t type, int reg)
{
type = jit_type_normalize(type);
if(type)
{
if(type->kind == JIT_TYPE_LONG || type->kind == JIT_TYPE_ULONG)
{
return jit_reg_other_reg(reg);
}
else if(type->kind == JIT_TYPE_FLOAT64 || type->kind == JIT_TYPE_NFLOAT)
{
if(reg == ARM_REG_R0)
{
return jit_reg_other_reg(reg);
}
}
}
return -1;
}
#endif