version 1.1.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; |