|
version 1.1, 2012/02/21 23:05:52
|
version 1.1.1.2, 2012/02/21 23:50:25
|
|
Line 1
|
Line 1
|
| /* |
/* |
| * Stack-less Just-In-Time compiler |
* Stack-less Just-In-Time compiler |
| * |
* |
| * Copyright 2009-2010 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. | * Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. |
| * |
* |
| * Redistribution and use in source and binary forms, with or without modification, are |
* Redistribution and use in source and binary forms, with or without modification, are |
| * permitted provided that the following conditions are met: |
* permitted provided that the following conditions are met: |
|
Line 26
|
Line 26
|
| |
|
| SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() |
SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() |
| { |
{ |
| return "arm-thumb2"; | return "ARM-Thumb2" SLJIT_CPUINFO; |
| } |
} |
| |
|
| /* Last register + 1. */ |
/* Last register + 1. */ |
|
Line 38 SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_p
|
Line 38 SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_p
|
| #define TMP_FREG1 (SLJIT_FLOAT_REG4 + 1) |
#define TMP_FREG1 (SLJIT_FLOAT_REG4 + 1) |
| #define TMP_FREG2 (SLJIT_FLOAT_REG4 + 2) |
#define TMP_FREG2 (SLJIT_FLOAT_REG4 + 2) |
| |
|
| /* See sljit_emit_enter if you want to change them. */ | /* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */ |
| static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = { |
static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = { |
| 0, 0, 1, 2, 12, 5, 6, 7, 8, 10, 11, 13, 3, 4, 14, 15 |
0, 0, 1, 2, 12, 5, 6, 7, 8, 10, 11, 13, 3, 4, 14, 15 |
| }; |
}; |
|
Line 122 typedef sljit_ui sljit_ins;
|
Line 122 typedef sljit_ui sljit_ins;
|
| #define LSR_W 0xfa20f000 |
#define LSR_W 0xfa20f000 |
| #define LSR_WI 0xea4f0010 |
#define LSR_WI 0xea4f0010 |
| #define MOV 0x4600 |
#define MOV 0x4600 |
| |
#define MOVS 0x0000 |
| #define MOVSI 0x2000 |
#define MOVSI 0x2000 |
| #define MOVT 0xf2c00000 |
#define MOVT 0xf2c00000 |
| #define MOVW 0xf2400000 |
#define MOVW 0xf2400000 |
| |
#define MOV_W 0xea4f0000 |
| #define MOV_WI 0xf04f0000 |
#define MOV_WI 0xf04f0000 |
| #define MUL 0xfb00f000 |
#define MUL 0xfb00f000 |
| #define MVNS 0x43c0 |
#define MVNS 0x43c0 |
|
Line 158 typedef sljit_ui sljit_ins;
|
Line 160 typedef sljit_ui sljit_ins;
|
| #define SXTH 0xb200 |
#define SXTH 0xb200 |
| #define SXTH_W 0xfa0ff080 |
#define SXTH_W 0xfa0ff080 |
| #define TST 0x4200 |
#define TST 0x4200 |
| |
#define UMULL 0xfba00000 |
| #define UXTB 0xb2c0 |
#define UXTB 0xb2c0 |
| #define UXTB_W 0xfa5ff080 |
#define UXTB_W 0xfa5ff080 |
| #define UXTH 0xb280 |
#define UXTH 0xb280 |
|
Line 616 static int emit_op_imm(struct sljit_compiler *compiler
|
Line 619 static int emit_op_imm(struct sljit_compiler *compiler
|
| case SLJIT_SHL: |
case SLJIT_SHL: |
| if (flags & ARG2_IMM) { |
if (flags & ARG2_IMM) { |
| imm &= 0x1f; |
imm &= 0x1f; |
| |
if (imm == 0) { |
| |
if (!(flags & SET_FLAGS)) |
| |
return push_inst16(compiler, MOV | SET_REGS44(dst, reg)); |
| |
if (IS_2_LO_REGS(dst, reg)) |
| |
return push_inst16(compiler, MOVS | RD3(dst) | RN3(reg)); |
| |
return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(dst) | RM4(reg)); |
| |
} |
| if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, reg)) |
if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, reg)) |
| return push_inst16(compiler, LSLSI | RD3(dst) | RN3(reg) | (imm << 6)); |
return push_inst16(compiler, LSLSI | RD3(dst) | RN3(reg) | (imm << 6)); |
| return push_inst32(compiler, LSL_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); |
return push_inst32(compiler, LSL_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); |
|
Line 624 static int emit_op_imm(struct sljit_compiler *compiler
|
Line 634 static int emit_op_imm(struct sljit_compiler *compiler
|
| case SLJIT_LSHR: |
case SLJIT_LSHR: |
| if (flags & ARG2_IMM) { |
if (flags & ARG2_IMM) { |
| imm &= 0x1f; |
imm &= 0x1f; |
| |
if (imm == 0) { |
| |
if (!(flags & SET_FLAGS)) |
| |
return push_inst16(compiler, MOV | SET_REGS44(dst, reg)); |
| |
if (IS_2_LO_REGS(dst, reg)) |
| |
return push_inst16(compiler, MOVS | RD3(dst) | RN3(reg)); |
| |
return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(dst) | RM4(reg)); |
| |
} |
| if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, reg)) |
if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, reg)) |
| return push_inst16(compiler, LSRSI | RD3(dst) | RN3(reg) | (imm << 6)); |
return push_inst16(compiler, LSRSI | RD3(dst) | RN3(reg) | (imm << 6)); |
| return push_inst32(compiler, LSR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); |
return push_inst32(compiler, LSR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); |
|
Line 632 static int emit_op_imm(struct sljit_compiler *compiler
|
Line 649 static int emit_op_imm(struct sljit_compiler *compiler
|
| case SLJIT_ASHR: |
case SLJIT_ASHR: |
| if (flags & ARG2_IMM) { |
if (flags & ARG2_IMM) { |
| imm &= 0x1f; |
imm &= 0x1f; |
| |
if (imm == 0) { |
| |
if (!(flags & SET_FLAGS)) |
| |
return push_inst16(compiler, MOV | SET_REGS44(dst, reg)); |
| |
if (IS_2_LO_REGS(dst, reg)) |
| |
return push_inst16(compiler, MOVS | RD3(dst) | RN3(reg)); |
| |
return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(dst) | RM4(reg)); |
| |
} |
| if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, reg)) |
if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(dst, reg)) |
| return push_inst16(compiler, ASRSI | RD3(dst) | RN3(reg) | (imm << 6)); |
return push_inst16(compiler, ASRSI | RD3(dst) | RN3(reg) | (imm << 6)); |
| return push_inst32(compiler, ASR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); |
return push_inst32(compiler, ASR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); |
|
Line 1077 static SLJIT_INLINE int emit_op_mem(struct sljit_compi
|
Line 1101 static SLJIT_INLINE int emit_op_mem(struct sljit_compi
|
| return getput_arg(compiler, flags, reg, arg, argw, 0, 0); |
return getput_arg(compiler, flags, reg, arg, argw, 0, 0); |
| } |
} |
| |
|
| SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int generals, int local_size) | SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) |
| { |
{ |
| int size; |
int size; |
| sljit_ins push; |
sljit_ins push; |
| |
|
| CHECK_ERROR(); |
CHECK_ERROR(); |
| check_sljit_emit_enter(compiler, args, temporaries, generals, local_size); | check_sljit_emit_enter(compiler, args, temporaries, saveds, local_size); |
| |
|
| compiler->temporaries = temporaries; |
compiler->temporaries = temporaries; |
| compiler->generals = generals; | compiler->saveds = saveds; |
| |
|
| push = (1 << 4); |
push = (1 << 4); |
| if (generals >= 5) | if (saveds >= 5) |
| push |= 1 << 11; |
push |= 1 << 11; |
| if (generals >= 4) | if (saveds >= 4) |
| push |= 1 << 10; |
push |= 1 << 10; |
| if (generals >= 3) | if (saveds >= 3) |
| push |= 1 << 8; |
push |= 1 << 8; |
| if (generals >= 2) | if (saveds >= 2) |
| push |= 1 << 7; |
push |= 1 << 7; |
| if (generals >= 1) | if (saveds >= 1) |
| push |= 1 << 6; |
push |= 1 << 6; |
| if (temporaries >= 5) |
if (temporaries >= 5) |
| push |= 1 << 5; |
push |= 1 << 5; |
| FAIL_IF(generals >= 3 | FAIL_IF(saveds >= 3 |
| ? push_inst32(compiler, PUSH_W | (1 << 14) | push) |
? push_inst32(compiler, PUSH_W | (1 << 14) | push) |
| : push_inst16(compiler, PUSH | push)); |
: push_inst16(compiler, PUSH | push)); |
| |
|
| /* Stack must be aligned to 8 bytes: */ |
/* Stack must be aligned to 8 bytes: */ |
| size = (3 + generals) * sizeof(sljit_uw); | size = (3 + saveds) * sizeof(sljit_uw); |
| local_size += size; |
local_size += size; |
| local_size = (local_size + 7) & ~7; |
local_size = (local_size + 7) & ~7; |
| local_size -= size; |
local_size -= size; |
|
Line 1119 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct s
|
Line 1143 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct s
|
| } |
} |
| |
|
| if (args >= 1) |
if (args >= 1) |
| FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_GENERAL_REG1, SLJIT_TEMPORARY_REG1))); | FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_SAVED_REG1, SLJIT_TEMPORARY_REG1))); |
| if (args >= 2) |
if (args >= 2) |
| FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_GENERAL_REG2, SLJIT_TEMPORARY_REG2))); | FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_SAVED_REG2, SLJIT_TEMPORARY_REG2))); |
| if (args >= 3) |
if (args >= 3) |
| FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_GENERAL_REG3, SLJIT_TEMPORARY_REG3))); | FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_SAVED_REG3, SLJIT_TEMPORARY_REG3))); |
| |
|
| return SLJIT_SUCCESS; |
return SLJIT_SUCCESS; |
| } |
} |
| |
|
| SLJIT_API_FUNC_ATTRIBUTE void sljit_fake_enter(struct sljit_compiler *compiler, int args, int temporaries, int generals, int local_size) | SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) |
| { |
{ |
| int size; |
int size; |
| |
|
| CHECK_ERROR_VOID(); |
CHECK_ERROR_VOID(); |
| check_sljit_fake_enter(compiler, args, temporaries, generals, local_size); | check_sljit_set_context(compiler, args, temporaries, saveds, local_size); |
| |
|
| compiler->temporaries = temporaries; |
compiler->temporaries = temporaries; |
| compiler->generals = generals; | compiler->saveds = saveds; |
| |
|
| size = (3 + generals) * sizeof(sljit_uw); | size = (3 + saveds) * sizeof(sljit_uw); |
| local_size += size; |
local_size += size; |
| local_size = (local_size + 7) & ~7; |
local_size = (local_size + 7) & ~7; |
| local_size -= size; |
local_size -= size; |
| compiler->local_size = local_size; |
compiler->local_size = local_size; |
| } |
} |
| |
|
| SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int src, sljit_w srcw) | SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw) |
| { |
{ |
| sljit_ins pop; |
sljit_ins pop; |
| |
|
| CHECK_ERROR(); |
CHECK_ERROR(); |
| check_sljit_emit_return(compiler, src, srcw); | check_sljit_emit_return(compiler, op, src, srcw); |
| |
|
| if (src != SLJIT_UNUSED && src != SLJIT_RETURN_REG) { | FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); |
| if (src >= SLJIT_TEMPORARY_REG1 && src <= TMP_REG3) | |
| FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_RETURN_REG, src))); | |
| else | |
| FAIL_IF(emit_op_mem(compiler, WORD_SIZE, SLJIT_RETURN_REG, src, srcw)); | |
| } | |
| |
|
| if (compiler->local_size > 0) { |
if (compiler->local_size > 0) { |
| if (compiler->local_size <= (127 << 2)) |
if (compiler->local_size <= (127 << 2)) |
|
Line 1167 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct
|
Line 1186 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct
|
| } |
} |
| |
|
| pop = (1 << 4); |
pop = (1 << 4); |
| if (compiler->generals >= 5) | if (compiler->saveds >= 5) |
| pop |= 1 << 11; |
pop |= 1 << 11; |
| if (compiler->generals >= 4) | if (compiler->saveds >= 4) |
| pop |= 1 << 10; |
pop |= 1 << 10; |
| if (compiler->generals >= 3) | if (compiler->saveds >= 3) |
| pop |= 1 << 8; |
pop |= 1 << 8; |
| if (compiler->generals >= 2) | if (compiler->saveds >= 2) |
| pop |= 1 << 7; |
pop |= 1 << 7; |
| if (compiler->generals >= 1) | if (compiler->saveds >= 1) |
| pop |= 1 << 6; |
pop |= 1 << 6; |
| if (compiler->temporaries >= 5) |
if (compiler->temporaries >= 5) |
| pop |= 1 << 5; |
pop |= 1 << 5; |
| return compiler->generals >= 3 | return compiler->saveds >= 3 |
| ? push_inst32(compiler, POP_W | (1 << 15) | pop) |
? push_inst32(compiler, POP_W | (1 << 15) | pop) |
| : push_inst16(compiler, POP | pop); |
: push_inst16(compiler, POP | pop); |
| } |
} |
|
Line 1188 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct
|
Line 1207 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct
|
| /* Operators */ |
/* Operators */ |
| /* --------------------------------------------------------------------- */ |
/* --------------------------------------------------------------------- */ |
| |
|
| |
#ifdef __cplusplus |
| |
extern "C" { |
| |
#endif |
| |
|
| |
#if defined(__GNUC__) |
| |
extern unsigned int __aeabi_uidivmod(unsigned numerator, unsigned denominator); |
| |
extern unsigned int __aeabi_idivmod(unsigned numerator, unsigned denominator); |
| |
#else |
| |
#error "Software divmod functions are needed" |
| |
#endif |
| |
|
| |
#ifdef __cplusplus |
| |
} |
| |
#endif |
| |
|
| SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op) |
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op) |
| { |
{ |
| CHECK_ERROR(); |
CHECK_ERROR(); |
|
Line 1201 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct slj
|
Line 1235 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct slj
|
| case SLJIT_NOP: |
case SLJIT_NOP: |
| push_inst16(compiler, NOP); |
push_inst16(compiler, NOP); |
| break; |
break; |
| |
case SLJIT_UMUL: |
| |
case SLJIT_SMUL: |
| |
return push_inst32(compiler, (op == SLJIT_UMUL ? UMULL : SMULL) |
| |
| (reg_map[SLJIT_TEMPORARY_REG2] << 8) |
| |
| (reg_map[SLJIT_TEMPORARY_REG1] << 12) |
| |
| (reg_map[SLJIT_TEMPORARY_REG1] << 16) |
| |
| reg_map[SLJIT_TEMPORARY_REG2]); |
| |
case SLJIT_UDIV: |
| |
case SLJIT_SDIV: |
| |
if (compiler->temporaries >= 4) { |
| |
FAIL_IF(push_inst32(compiler, 0xf84d2d04 /* str r2, [sp, #-4]! */)); |
| |
FAIL_IF(push_inst32(compiler, 0xf84dcd04 /* str ip, [sp, #-4]! */)); |
| |
} else if (compiler->temporaries >= 3) |
| |
FAIL_IF(push_inst32(compiler, 0xf84d2d08 /* str r2, [sp, #-8]! */)); |
| |
#if defined(__GNUC__) |
| |
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM, |
| |
(op == SLJIT_UDIV ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod)))); |
| |
#else |
| |
#error "Software divmod functions are needed" |
| |
#endif |
| |
if (compiler->temporaries >= 4) { |
| |
FAIL_IF(push_inst32(compiler, 0xf85dcb04 /* ldr ip, [sp], #4 */)); |
| |
return push_inst32(compiler, 0xf85d2b04 /* ldr r2, [sp], #4 */); |
| |
} else if (compiler->temporaries >= 3) |
| |
return push_inst32(compiler, 0xf85d2b08 /* ldr r2, [sp], #8 */); |
| |
return SLJIT_SUCCESS; |
| } |
} |
| |
|
| return SLJIT_SUCCESS; |
return SLJIT_SUCCESS; |
|
Line 1412 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct slj
|
Line 1472 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct slj
|
| return SLJIT_SUCCESS; |
return SLJIT_SUCCESS; |
| } |
} |
| |
|
| |
SLJIT_API_FUNC_ATTRIBUTE int sljit_get_register_index(int reg) |
| |
{ |
| |
check_sljit_get_register_index(reg); |
| |
return reg_map[reg]; |
| |
} |
| |
|
| |
SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compiler, |
| |
void *instruction, int size) |
| |
{ |
| |
CHECK_ERROR(); |
| |
check_sljit_emit_op_custom(compiler, instruction, size); |
| |
SLJIT_ASSERT(size == 2 || size == 4); |
| |
|
| |
if (size == 2) |
| |
return push_inst16(compiler, *(sljit_uh*)instruction); |
| |
return push_inst32(compiler, *(sljit_ins*)instruction); |
| |
} |
| |
|
| /* --------------------------------------------------------------------- */ |
/* --------------------------------------------------------------------- */ |
| /* Floating point operators */ |
/* Floating point operators */ |
| /* --------------------------------------------------------------------- */ |
/* --------------------------------------------------------------------- */ |
|
Line 1567 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sl
|
Line 1645 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sl
|
| /* Other instructions */ |
/* Other instructions */ |
| /* --------------------------------------------------------------------- */ |
/* --------------------------------------------------------------------- */ |
| |
|
| SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw, int args, int temporaries, int generals, int local_size) | SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw, int args, int temporaries, int saveds, int local_size) |
| { |
{ |
| int size; |
int size; |
| |
|
| CHECK_ERROR(); |
CHECK_ERROR(); |
| check_sljit_emit_fast_enter(compiler, dst, dstw, args, temporaries, generals, local_size); | check_sljit_emit_fast_enter(compiler, dst, dstw, args, temporaries, saveds, local_size); |
| |
|
| compiler->temporaries = temporaries; |
compiler->temporaries = temporaries; |
| compiler->generals = generals; | compiler->saveds = saveds; |
| |
|
| size = (3 + generals) * sizeof(sljit_uw); | size = (3 + saveds) * sizeof(sljit_uw); |
| local_size += size; |
local_size += size; |
| local_size = (local_size + 7) & ~7; |
local_size = (local_size + 7) & ~7; |
| local_size -= size; |
local_size -= size; |