Alien-LibJIT
view release on metacpan or search on metacpan
libjit/jit/jit-gen-arm.h view on Meta::CPAN
* Move an immediate value into a register. This is hard because
* ARM lacks an instruction to load a 32-bit immediate value directly.
* We handle the simple cases and then bail out to a function for the rest.
*/
#define arm_mov_reg_imm8(inst,reg,imm) \
do { \
arm_alu_reg_imm8((inst), ARM_MOV, (reg), 0, (imm)); \
} while (0)
#define arm_mov_reg_imm8_rotate(inst,reg,imm,rotate) \
do { \
arm_alu_reg_imm8_rotate((inst), ARM_MOV, (reg), \
0, (imm), (rotate)); \
} while (0)
extern void _arm_mov_reg_imm
(arm_inst_buf *inst, int reg, int value, int execute_prefix);
extern int arm_is_complex_imm(int value);
/**
* Moves the immediate value imm into register reg.
*
* In case imm is > 255, it builds the value one byte at a time, by calling _arm_mov_reg_imm
* This is done by using a big number of instruction.
* In that case, using mov_reg_imm (defined in jit-rules-arm.c is probably a better idea, when possible
*/
#define arm_mov_reg_imm(inst,reg,imm) \
do { \
int __imm = (int)(imm); \
if(__imm >= 0 && __imm < 256) \
{ \
arm_mov_reg_imm8((inst), (reg), __imm); \
} \
else if((reg) == ARM_PC) \
{ \
_arm_mov_reg_imm \
(&(inst), ARM_WORK, __imm, arm_execute); \
arm_mov_reg_reg((inst), ARM_PC, ARM_WORK); \
} \
else if(__imm > -256 && __imm < 0) \
{ \
arm_mov_reg_imm8((inst), (reg), ~(__imm)); \
arm_alu_reg((inst), ARM_MVN, (reg), (reg)); \
} \
else \
{ \
_arm_mov_reg_imm(&(inst), (reg), __imm, arm_execute); \
} \
} while (0)
#define ARM_NOBASEREG (-1)
/**
* LDR (Load Register), LDRB (Load Register Byte)
* Load the content of the memory area of size "size" at position basereg+disp+(indexreg<<shift) into the 32-bit "reg", with zero-extension.
* "scratchreg" is a scratch register that has to be asked to the register allocator; it is
* used only when disp!=0; if disp==0, it can have whatever value, since it won't be used
*/
#define arm_mov_reg_memindex(inst,reg,basereg,disp,indexreg,shift,size,scratchreg) \
do { \
if (basereg==ARM_NOBASEREG) \
{ \
fprintf(stderr, "TODO(NOBASEREG) at %s, %d\n", __FILE__, (int)__LINE__); \
} \
else \
{ \
/* Add the displacement (only if needed)*/\
int tempreg=(basereg); \
if (disp!=0) \
{ \
tempreg=(scratchreg); \
assert(tempreg!=basereg); \
assert(tempreg!=indexreg); \
arm_alu_reg_imm((inst), ARM_ADD, (tempreg), (basereg), (disp)); \
} \
/* Load the content, depending on its size */ \
switch ((size)) { \
case 1: arm_load_memindex_either(inst,reg,(tempreg),indexreg,shift,0x00400000); break; \
case 2: arm_load_memindex_either(inst,reg,tempreg,indexreg,shift,0); \
arm_shift_reg_imm8((inst), ARM_SHL, (reg), (reg), 16); \
arm_shift_reg_imm8((inst), ARM_SHR, (reg), (reg), 16); \
break; \
case 4: arm_load_memindex_either(inst,reg,tempreg,indexreg,shift,0); break; \
default: assert (0); \
} \
} \
} while (0)
/**
* Store the content of "reg" into a memory area of size "size" at position basereg+disp+(indexreg<<shift)
* NB: the scratch register has to be asked to the register allocator.
* It can't be ARM_WORK, since it's already used
*/
#define arm_mov_memindex_reg(inst,basereg,disp,indexreg,shift,reg,size,scratchreg) \
do { \
if (basereg==ARM_NOBASEREG) \
{ \
fprintf(stderr, "TODO(NOBASEREG) at %s, %d\n", __FILE__, (int)__LINE__); \
} \
else \
{ \
arm_shift_reg_imm8((inst), ARM_SHL, (ARM_WORK), (indexreg), (shift)); \
arm_alu_reg_reg((inst), ARM_ADD, (scratchreg), (basereg), ARM_WORK); \
arm_mov_membase_reg((inst),(scratchreg),(disp),(reg),(size)) \
} \
} while (0);
/*
* Stores the content of register "reg" in memory, at position "mem" with size "size"
* NB: destroys the content of ARM_WORK
*/
#define arm_mov_mem_reg(inst,mem,reg,size) \
do { \
arm_mov_reg_imm((inst), ARM_WORK, (mem)); \
switch ((size)) { \
case 1: arm_store_membase_byte((inst), (reg), ARM_WORK, 0); break; \
case 2: arm_store_membase_short((inst), (reg), ARM_WORK, 0); break; \
case 4: arm_store_membase((inst), (reg), ARM_WORK, 0); break; \
default: jit_assert(0); \
} \
} while (0)
/*
* Stores the content of "imm" in memory, at position "mem" with size "size". Uses a scratch register (scratchreg),
* that has to be asked to the register allocator via the [scratch reg] parameter in the definition of the OPCODE.
* NB: destroys the content of ARM_WORK
*/
#define arm_mov_mem_imm(inst,mem,imm,size,scratchreg) \
do { \
arm_mov_reg_imm((inst), (scratchreg), (imm)); \
arm_mov_reg_imm((inst), ARM_WORK, (mem)); \
switch ((size)) { \
case 1: arm_store_membase_byte((inst), (scratchreg), ARM_WORK, 0); break; \
case 2: arm_store_membase_short((inst), (scratchreg), ARM_WORK, 0); break; \
case 4: arm_store_membase((inst), (scratchreg), ARM_WORK, 0); break; \
default: assert(0); \
} \
} while (0)
/**
* Set "size" bytes at position basereg+disp at the value of imm
* NB: destroys the content of scratchreg. A good choice for scratchreg is ARM_WORK,
* unless the value of disp is too big to be handled by arm_store_membase_either. In that case,
* it's better to require the allocation of a scratch reg by adding the parameter [scratch reg] at the end
* of the parameters of the rule inside jit-rules-arm.ins that's calling this function.
*/
#define arm_mov_membase_imm(inst,basereg,disp,imm,size,scratchreg) \
do { \
arm_mov_reg_imm((inst), (scratchreg), imm); \
arm_mov_membase_reg((inst), (basereg), (disp), (scratchreg), (size)); \
} while(0);
/**
* Set "size" bytes at position basereg+disp at the value of reg
* NB: might destroy the content of ARM_WORK because of arm_store_membase
*/
#define arm_mov_membase_reg(inst,basereg,disp,reg,size) \
do { \
( run in 0.488 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )