Path: blob/master/thirdparty/pcre2/deps/sljit/sljit_src/sljitNativeARM_32.c
22129 views
/*1* Stack-less Just-In-Time compiler2*3* Copyright Zoltan Herczeg ([email protected]). All rights reserved.4*5* Redistribution and use in source and binary forms, with or without modification, are6* permitted provided that the following conditions are met:7*8* 1. Redistributions of source code must retain the above copyright notice, this list of9* conditions and the following disclaimer.10*11* 2. Redistributions in binary form must reproduce the above copyright notice, this list12* of conditions and the following disclaimer in the documentation and/or other materials13* provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY16* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES17* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT18* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,19* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED20* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR21* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN22* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN23* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.24*/2526#ifdef __SOFTFP__27#define ARM_ABI_INFO " ABI:softfp"28#else29#define ARM_ABI_INFO " ABI:hardfp"30#endif3132SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)33{34#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)35return "ARMv7" SLJIT_CPUINFO ARM_ABI_INFO;36#elif (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)37return "ARMv6" SLJIT_CPUINFO ARM_ABI_INFO;38#else39#error "Internal error: Unknown ARM architecture"40#endif41}4243/* Length of an instruction word. */44typedef sljit_u32 sljit_ins;4546/* Last register + 1. */47#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)48#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)49#define TMP_PC (SLJIT_NUMBER_OF_REGISTERS + 4)5051#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)52#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)5354/* In ARM instruction words.55Cache lines are usually 32 byte aligned. */56#define CONST_POOL_ALIGNMENT 857#define CONST_POOL_EMPTY 0xffffffff5859#define ALIGN_INSTRUCTION(ptr) \60(sljit_ins*)(((sljit_ins)(ptr) + (CONST_POOL_ALIGNMENT * sizeof(sljit_ins)) - 1) & ~((CONST_POOL_ALIGNMENT * sizeof(sljit_ins)) - 1))61#define MAX_DIFFERENCE(max_diff) \62(((max_diff) / (sljit_s32)sizeof(sljit_ins)) - (CONST_POOL_ALIGNMENT - 1))6364/* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */65static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {660, 0, 1, 2, 3, 11, 10, 9, 8, 7, 6, 5, 4, 13, 12, 14, 1567};6869static const sljit_u8 freg_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1) + 1] = {700,710, 1, 2, 3, 4, 5, 15, 14, 13, 12, 11, 10, 9, 8,727, 6,730, 1, 2, 3, 4, 5, 15, 14, 13, 12, 11, 10, 9, 8,747, 675};7677static const sljit_u8 freg_ebit_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1) + 1] = {780,790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,800, 0,811, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,821, 183};8485#define RM(rm) ((sljit_ins)reg_map[rm])86#define RM8(rm) ((sljit_ins)reg_map[rm] << 8)87#define RD(rd) ((sljit_ins)reg_map[rd] << 12)88#define RN(rn) ((sljit_ins)reg_map[rn] << 16)8990#define VM(vm) (((sljit_ins)freg_map[vm]) | ((sljit_ins)freg_ebit_map[vm] << 5))91#define VD(vd) (((sljit_ins)freg_map[vd] << 12) | ((sljit_ins)freg_ebit_map[vd] << 22))92#define VN(vn) (((sljit_ins)freg_map[vn] << 16) | ((sljit_ins)freg_ebit_map[vn] << 7))9394/* --------------------------------------------------------------------- */95/* Instruction forms */96/* --------------------------------------------------------------------- */9798/* The instruction includes the AL condition.99INST_NAME - CONDITIONAL remove this flag. */100#define COND_MASK 0xf0000000101#define CONDITIONAL 0xe0000000102#define PUSH_POOL 0xff000000103104#define ADC 0xe0a00000105#define ADD 0xe0800000106#define AND 0xe0000000107#define B 0xea000000108#define BIC 0xe1c00000109#define BKPT 0xe1200070110#define BL 0xeb000000111#define BLX 0xe12fff30112#define BX 0xe12fff10113#define CLZ 0xe16f0f10114#define CMN 0xe1600000115#define CMP 0xe1400000116#define DMB_SY 0xf57ff05f117#define EOR 0xe0200000118#define LDR 0xe5100000119#define LDR_POST 0xe4100000120#define LDREX 0xe1900f9f121#define LDREXB 0xe1d00f9f122#define LDREXH 0xe1f00f9f123#define MLA 0xe0200090124#define MOV 0xe1a00000125#define MUL 0xe0000090126#define MVN 0xe1e00000127#define NOP 0xe1a00000128#define ORR 0xe1800000129#define PUSH 0xe92d0000130#define POP 0xe8bd0000131#define REV 0xe6bf0f30132#define REV16 0xe6bf0fb0133#define RSB 0xe0600000134#define RSC 0xe0e00000135#define SBC 0xe0c00000136#define SMULL 0xe0c00090137#define STR 0xe5000000138#define STREX 0xe1800f90139#define STREXB 0xe1c00f90140#define STREXH 0xe1e00f90141#define SUB 0xe0400000142#define SXTB 0xe6af0070143#define SXTH 0xe6bf0070144#define TST 0xe1000000145#define UMULL 0xe0800090146#define UXTB 0xe6ef0070147#define UXTH 0xe6ff0070148#define VABS_F32 0xeeb00ac0149#define VADD_F32 0xee300a00150#define VAND 0xf2000110151#define VCMP_F32 0xeeb40a40152#define VCVT_F32_S32 0xeeb80ac0153#define VCVT_F32_U32 0xeeb80a40154#define VCVT_F64_F32 0xeeb70ac0155#define VCVT_S32_F32 0xeebd0ac0156#define VDIV_F32 0xee800a00157#define VDUP 0xee800b10158#define VDUP_s 0xf3b00c00159#define VEOR 0xf3000110160#define VLD1 0xf4200000161#define VLD1_r 0xf4a00c00162#define VLD1_s 0xf4a00000163#define VLDR_F32 0xed100a00164#define VMOV_F32 0xeeb00a40165#define VMOV 0xee000a10166#define VMOV2 0xec400a10167#define VMOV_i 0xf2800010168#define VMOV_s 0xee000b10169#define VMOVN 0xf3b20200170#define VMRS 0xeef1fa10171#define VMUL_F32 0xee200a00172#define VNEG_F32 0xeeb10a40173#define VORR 0xf2200110174#define VPOP 0xecbd0b00175#define VPUSH 0xed2d0b00176#define VSHLL 0xf2800a10177#define VSHR 0xf2800010178#define VSRA 0xf2800110179#define VST1 0xf4000000180#define VST1_s 0xf4800000181#define VSTR_F32 0xed000a00182#define VSUB_F32 0xee300a40183#define VTBL 0xf3b00800184185#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)186/* Arm v7 specific instructions. */187#define MOVT 0xe3400000188#define MOVW 0xe3000000189#define RBIT 0xe6ff0f30190#endif191192#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)193194static sljit_s32 function_check_is_freg(struct sljit_compiler *compiler, sljit_s32 fr, sljit_s32 is_32)195{196if (compiler->scratches == -1)197return 0;198199if (is_32 && fr >= SLJIT_F64_SECOND(SLJIT_FR0))200fr -= SLJIT_F64_SECOND(0);201202return (fr >= SLJIT_FR0 && fr < (SLJIT_FR0 + compiler->real_fscratches))203|| (fr > (SLJIT_FS0 - compiler->real_fsaveds) && fr <= SLJIT_FS0)204|| (fr >= SLJIT_TMP_FREGISTER_BASE && fr < (SLJIT_TMP_FREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS));205}206207static sljit_s32 function_check_is_vreg(struct sljit_compiler *compiler, sljit_s32 vr, sljit_s32 type)208{209sljit_s32 vr_low = vr;210211if (compiler->scratches == -1)212return 0;213214if (SLJIT_SIMD_GET_REG_SIZE(type) == 4) {215vr += (vr & 0x1);216vr_low = vr - 1;217}218219return (vr >= SLJIT_VR0 && vr < (SLJIT_VR0 + compiler->vscratches))220|| (vr_low > (SLJIT_VS0 - compiler->vsaveds) && vr_low <= SLJIT_VS0)221|| (vr >= SLJIT_TMP_VREGISTER_BASE && vr < (SLJIT_TMP_VREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_VECTOR_REGISTERS));222}223224#endif /* SLJIT_ARGUMENT_CHECKS */225226#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)227228static sljit_s32 push_cpool(struct sljit_compiler *compiler)229{230/* Pushing the constant pool into the instruction stream. */231sljit_ins* inst;232sljit_uw* cpool_ptr;233sljit_uw* cpool_end;234sljit_s32 i;235236/* The label could point the address after the constant pool. */237if (compiler->last_label && compiler->last_label->size == compiler->size)238compiler->last_label->size += compiler->cpool_fill + (CONST_POOL_ALIGNMENT - 1) + 1;239240SLJIT_ASSERT(compiler->cpool_fill > 0 && compiler->cpool_fill <= CPOOL_SIZE);241inst = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));242FAIL_IF(!inst);243compiler->size++;244*inst = 0xff000000 | compiler->cpool_fill;245246for (i = 0; i < CONST_POOL_ALIGNMENT - 1; i++) {247inst = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));248FAIL_IF(!inst);249compiler->size++;250*inst = 0;251}252253cpool_ptr = compiler->cpool;254cpool_end = cpool_ptr + compiler->cpool_fill;255while (cpool_ptr < cpool_end) {256inst = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));257FAIL_IF(!inst);258compiler->size++;259*inst = *cpool_ptr++;260}261compiler->cpool_diff = CONST_POOL_EMPTY;262compiler->cpool_fill = 0;263return SLJIT_SUCCESS;264}265266static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins inst)267{268sljit_ins* ptr;269270if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)))271FAIL_IF(push_cpool(compiler));272273ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));274FAIL_IF(!ptr);275compiler->size++;276*ptr = inst;277return SLJIT_SUCCESS;278}279280static sljit_s32 push_inst_with_literal(struct sljit_compiler *compiler, sljit_ins inst, sljit_uw literal)281{282sljit_ins* ptr;283sljit_uw cpool_index = CPOOL_SIZE;284sljit_uw* cpool_ptr;285sljit_uw* cpool_end;286sljit_u8* cpool_unique_ptr;287288if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)))289FAIL_IF(push_cpool(compiler));290else if (compiler->cpool_fill > 0) {291cpool_ptr = compiler->cpool;292cpool_end = cpool_ptr + compiler->cpool_fill;293cpool_unique_ptr = compiler->cpool_unique;294do {295if ((*cpool_ptr == literal) && !(*cpool_unique_ptr)) {296cpool_index = (sljit_uw)(cpool_ptr - compiler->cpool);297break;298}299cpool_ptr++;300cpool_unique_ptr++;301} while (cpool_ptr < cpool_end);302}303304if (cpool_index == CPOOL_SIZE) {305/* Must allocate a new entry in the literal pool. */306if (compiler->cpool_fill < CPOOL_SIZE) {307cpool_index = compiler->cpool_fill;308compiler->cpool_fill++;309}310else {311FAIL_IF(push_cpool(compiler));312cpool_index = 0;313compiler->cpool_fill = 1;314}315}316317SLJIT_ASSERT((inst & 0xfff) == 0);318ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));319FAIL_IF(!ptr);320compiler->size++;321*ptr = inst | cpool_index;322323compiler->cpool[cpool_index] = literal;324compiler->cpool_unique[cpool_index] = 0;325if (compiler->cpool_diff == CONST_POOL_EMPTY)326compiler->cpool_diff = compiler->size;327return SLJIT_SUCCESS;328}329330static sljit_s32 push_inst_with_unique_literal(struct sljit_compiler *compiler, sljit_ins inst, sljit_uw literal)331{332sljit_ins* ptr;333334if (SLJIT_UNLIKELY((compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)) || compiler->cpool_fill >= CPOOL_SIZE))335FAIL_IF(push_cpool(compiler));336337SLJIT_ASSERT(compiler->cpool_fill < CPOOL_SIZE && (inst & 0xfff) == 0);338ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));339FAIL_IF(!ptr);340compiler->size++;341*ptr = inst | compiler->cpool_fill;342343compiler->cpool[compiler->cpool_fill] = literal;344compiler->cpool_unique[compiler->cpool_fill] = 1;345compiler->cpool_fill++;346if (compiler->cpool_diff == CONST_POOL_EMPTY)347compiler->cpool_diff = compiler->size;348return SLJIT_SUCCESS;349}350351static SLJIT_INLINE sljit_s32 prepare_blx(struct sljit_compiler *compiler)352{353/* Place for at least two instruction (doesn't matter whether the first has a literal). */354if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4088)))355return push_cpool(compiler);356return SLJIT_SUCCESS;357}358359static SLJIT_INLINE sljit_s32 emit_blx(struct sljit_compiler *compiler)360{361/* Must follow tightly the previous instruction (to be able to convert it to bl instruction). */362SLJIT_ASSERT(compiler->cpool_diff == CONST_POOL_EMPTY || compiler->size - compiler->cpool_diff < MAX_DIFFERENCE(4092));363SLJIT_ASSERT(reg_map[TMP_REG1] != 14);364365return push_inst(compiler, BLX | RM(TMP_REG1));366}367368static sljit_uw patch_pc_relative_loads(sljit_uw *last_pc_patch, sljit_uw *code_ptr, sljit_uw* const_pool, sljit_uw cpool_size)369{370sljit_uw diff;371sljit_uw ind;372sljit_uw counter = 0;373sljit_uw* clear_const_pool = const_pool;374sljit_uw* clear_const_pool_end = const_pool + cpool_size;375376SLJIT_ASSERT(const_pool - code_ptr <= CONST_POOL_ALIGNMENT);377/* Set unused flag for all literals in the constant pool.378I.e.: unused literals can belong to branches, which can be encoded as B or BL.379We can "compress" the constant pool by discarding these literals. */380while (clear_const_pool < clear_const_pool_end)381*clear_const_pool++ = (sljit_uw)(-1);382383while (last_pc_patch < code_ptr) {384/* Data transfer instruction with Rn == r15. */385if ((*last_pc_patch & 0x0e4f0000) == 0x040f0000) {386diff = (sljit_uw)(const_pool - last_pc_patch);387ind = (*last_pc_patch) & 0xfff;388389/* Must be a load instruction with immediate offset. */390SLJIT_ASSERT(ind < cpool_size && !(*last_pc_patch & (1 << 25)) && (*last_pc_patch & (1 << 20)));391if ((sljit_s32)const_pool[ind] < 0) {392const_pool[ind] = counter;393ind = counter;394counter++;395}396else397ind = const_pool[ind];398399SLJIT_ASSERT(diff >= 1);400if (diff >= 2 || ind > 0) {401diff = (diff + (sljit_uw)ind - 2) << 2;402SLJIT_ASSERT(diff <= 0xfff);403*last_pc_patch = (*last_pc_patch & ~(sljit_uw)0xfff) | diff;404}405else406*last_pc_patch = (*last_pc_patch & ~(sljit_uw)(0xfff | (1 << 23))) | 0x004;407}408last_pc_patch++;409}410return counter;411}412413/* In some rare ocasions we may need future patches. The probability is close to 0 in practice. */414struct future_patch {415struct future_patch* next;416sljit_s32 index;417sljit_s32 value;418};419420static sljit_s32 resolve_const_pool_index(struct sljit_compiler *compiler, struct future_patch **first_patch, sljit_uw cpool_current_index, sljit_uw *cpool_start_address, sljit_uw *buf_ptr)421{422sljit_u32 value;423struct future_patch *curr_patch, *prev_patch;424425SLJIT_UNUSED_ARG(compiler);426427/* Using the values generated by patch_pc_relative_loads. */428if (!*first_patch)429value = cpool_start_address[cpool_current_index];430else {431curr_patch = *first_patch;432prev_patch = NULL;433while (1) {434if (!curr_patch) {435value = cpool_start_address[cpool_current_index];436break;437}438if ((sljit_uw)curr_patch->index == cpool_current_index) {439value = (sljit_uw)curr_patch->value;440if (prev_patch)441prev_patch->next = curr_patch->next;442else443*first_patch = curr_patch->next;444SLJIT_FREE(curr_patch, compiler->allocator_data);445break;446}447prev_patch = curr_patch;448curr_patch = curr_patch->next;449}450}451452if ((sljit_sw)value >= 0) {453if (value > cpool_current_index) {454curr_patch = (struct future_patch*)SLJIT_MALLOC(sizeof(struct future_patch), compiler->allocator_data);455if (!curr_patch) {456while (*first_patch) {457curr_patch = *first_patch;458*first_patch = (*first_patch)->next;459SLJIT_FREE(curr_patch, compiler->allocator_data);460}461return SLJIT_ERR_ALLOC_FAILED;462}463curr_patch->next = *first_patch;464curr_patch->index = (sljit_sw)value;465curr_patch->value = (sljit_sw)cpool_start_address[value];466*first_patch = curr_patch;467}468cpool_start_address[value] = *buf_ptr;469}470return SLJIT_SUCCESS;471}472473#else474475static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins inst)476{477sljit_ins* ptr;478479ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));480FAIL_IF(!ptr);481compiler->size++;482*ptr = inst;483return SLJIT_SUCCESS;484}485486static SLJIT_INLINE sljit_s32 emit_imm(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)487{488FAIL_IF(push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | ((sljit_u32)imm & 0xfff)));489return push_inst(compiler, MOVT | RD(reg) | ((imm >> 12) & 0xf0000) | (((sljit_u32)imm >> 16) & 0xfff));490}491492#endif493494static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw *code_ptr, sljit_uw *code, sljit_sw executable_offset)495{496sljit_sw diff;497sljit_uw target_addr;498sljit_uw jump_addr = (sljit_uw)code_ptr;499sljit_uw orig_addr = jump->addr;500SLJIT_UNUSED_ARG(executable_offset);501502#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)503jump->addr = jump_addr;504#endif505506if (jump->flags & SLJIT_REWRITABLE_JUMP)507return 0;508509#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)510if (jump->flags & IS_BL)511code_ptr--;512#endif /* SLJIT_CONFIG_ARM_V6 */513514if (jump->flags & JUMP_ADDR)515target_addr = jump->u.target;516else {517SLJIT_ASSERT(jump->u.label != NULL);518target_addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset);519520if (jump->u.label->size > orig_addr)521jump_addr = (sljit_uw)(code + orig_addr);522}523524diff = (sljit_sw)target_addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr + 8, executable_offset);525526/* Branch to Thumb code has not been optimized yet. */527if (diff & 0x3)528return 0;529530#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)531if (jump->flags & IS_BL) {532if (diff <= 0x01ffffff && diff >= -0x02000000) {533*code_ptr = (BL - CONDITIONAL) | (*(code_ptr + 1) & COND_MASK);534jump->flags |= PATCH_B;535return 1;536}537} else if (diff <= 0x01ffffff && diff >= -0x02000000) {538*code_ptr = (B - CONDITIONAL) | (*code_ptr & COND_MASK);539jump->flags |= PATCH_B;540}541#else /* !SLJIT_CONFIG_ARM_V6 */542if (diff <= 0x01ffffff && diff >= -0x02000000) {543*code_ptr = ((jump->flags & IS_BL) ? (BL - CONDITIONAL) : (B - CONDITIONAL)) | (*code_ptr & COND_MASK);544jump->flags |= PATCH_B;545return 1;546}547#endif /* SLJIT_CONFIG_ARM_V6 */548return 0;549}550551static void set_jump_addr(sljit_uw jump_ptr, sljit_sw executable_offset, sljit_uw new_addr, sljit_s32 flush_cache)552{553#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)554sljit_ins *ptr = (sljit_ins*)jump_ptr;555sljit_ins *inst = (sljit_ins*)ptr[0];556sljit_ins mov_pc = ptr[1];557sljit_s32 bl = (mov_pc & 0x0000f000) != RD(TMP_PC);558sljit_sw diff = (sljit_sw)(((sljit_sw)new_addr - (sljit_sw)(inst + 2) - executable_offset) >> 2);559560SLJIT_UNUSED_ARG(executable_offset);561562if (diff <= 0x7fffff && diff >= -0x800000) {563/* Turn to branch. */564if (!bl) {565if (flush_cache) {566SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);567}568inst[0] = (mov_pc & COND_MASK) | (B - CONDITIONAL) | (diff & 0xffffff);569if (flush_cache) {570SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);571inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);572SLJIT_CACHE_FLUSH(inst, inst + 1);573}574} else {575if (flush_cache) {576SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);577}578inst[0] = (mov_pc & COND_MASK) | (BL - CONDITIONAL) | (diff & 0xffffff);579inst[1] = NOP;580if (flush_cache) {581SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);582inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);583SLJIT_CACHE_FLUSH(inst, inst + 2);584}585}586} else {587/* Get the position of the constant. */588if (mov_pc & (1 << 23))589ptr = inst + ((mov_pc & 0xfff) >> 2) + 2;590else591ptr = inst + 1;592593if (*inst != mov_pc) {594if (flush_cache) {595SLJIT_UPDATE_WX_FLAGS(inst, inst + (!bl ? 1 : 2), 0);596}597inst[0] = mov_pc;598if (!bl) {599if (flush_cache) {600SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);601inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);602SLJIT_CACHE_FLUSH(inst, inst + 1);603}604} else {605inst[1] = BLX | RM(TMP_REG1);606if (flush_cache) {607SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);608inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);609SLJIT_CACHE_FLUSH(inst, inst + 2);610}611}612}613614if (flush_cache) {615SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 0);616}617618*ptr = new_addr;619620if (flush_cache) {621SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 1);622}623}624#else /* !SLJIT_CONFIG_ARM_V6 */625sljit_ins *inst = (sljit_ins*)jump_ptr;626627SLJIT_UNUSED_ARG(executable_offset);628629SLJIT_ASSERT((inst[0] & 0xfff00000) == MOVW && (inst[1] & 0xfff00000) == MOVT);630631if (flush_cache) {632SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);633}634635inst[0] = MOVW | (inst[0] & 0xf000) | ((new_addr << 4) & 0xf0000) | (new_addr & 0xfff);636inst[1] = MOVT | (inst[1] & 0xf000) | ((new_addr >> 12) & 0xf0000) | ((new_addr >> 16) & 0xfff);637638if (flush_cache) {639SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);640inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);641SLJIT_CACHE_FLUSH(inst, inst + 2);642}643#endif /* SLJIT_CONFIG_ARM_V6 */644}645646static sljit_uw get_imm(sljit_uw imm);647static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm);648static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg);649650static void set_const_value(sljit_uw addr, sljit_sw executable_offset, sljit_uw new_constant, sljit_s32 flush_cache)651{652#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)653sljit_ins *ptr = (sljit_ins*)addr;654sljit_ins *inst = (sljit_ins*)ptr[0];655sljit_uw ldr_literal = ptr[1];656sljit_uw src2;657658SLJIT_UNUSED_ARG(executable_offset);659660src2 = get_imm(new_constant);661if (src2) {662if (flush_cache) {663SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);664}665666*inst = 0xe3a00000 | (ldr_literal & 0xf000) | src2;667668if (flush_cache) {669SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);670inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);671SLJIT_CACHE_FLUSH(inst, inst + 1);672}673return;674}675676src2 = get_imm(~new_constant);677if (src2) {678if (flush_cache) {679SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);680}681682*inst = 0xe3e00000 | (ldr_literal & 0xf000) | src2;683684if (flush_cache) {685SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);686inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);687SLJIT_CACHE_FLUSH(inst, inst + 1);688}689return;690}691692if (ldr_literal & (1 << 23))693ptr = inst + ((ldr_literal & 0xfff) >> 2) + 2;694else695ptr = inst + 1;696697if (*inst != ldr_literal) {698if (flush_cache) {699SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);700}701702*inst = ldr_literal;703704if (flush_cache) {705SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);706inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);707SLJIT_CACHE_FLUSH(inst, inst + 1);708}709}710711if (flush_cache) {712SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 0);713}714715*ptr = new_constant;716717if (flush_cache) {718SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 1);719}720#else /* !SLJIT_CONFIG_ARM_V6 */721sljit_ins *inst = (sljit_ins*)addr;722723SLJIT_UNUSED_ARG(executable_offset);724725SLJIT_ASSERT((inst[0] & 0xfff00000) == MOVW && (inst[1] & 0xfff00000) == MOVT);726727if (flush_cache) {728SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);729}730731inst[0] = MOVW | (inst[0] & 0xf000) | ((new_constant << 4) & 0xf0000) | (new_constant & 0xfff);732inst[1] = MOVT | (inst[1] & 0xf000) | ((new_constant >> 12) & 0xf0000) | ((new_constant >> 16) & 0xfff);733734if (flush_cache) {735SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);736inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);737SLJIT_CACHE_FLUSH(inst, inst + 2);738}739#endif /* SLJIT_CONFIG_ARM_V6 */740}741742static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)743{744sljit_uw addr;745sljit_uw jump_addr = (sljit_uw)code_ptr;746sljit_sw diff;747SLJIT_UNUSED_ARG(executable_offset);748749if (jump->flags & JUMP_ADDR)750addr = jump->u.target;751else {752addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset);753754if (jump->u.label->size > jump->addr)755jump_addr = (sljit_uw)(code + jump->addr);756}757758/* The pc+8 offset is represented by the 2 * SSIZE_OF(ins) below. */759diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr, executable_offset);760761if ((diff & 0x3) == 0 && diff <= (0x3fc + 2 * SSIZE_OF(ins)) && diff >= (-0x3fc + 2 * SSIZE_OF(ins))) {762jump->flags |= PATCH_B;763return 0;764}765766#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)767return 0;768#else /* !SLJIT_CONFIG_ARM_V6 */769return 1;770#endif /* SLJIT_CONFIG_ARM_V6 */771}772773static SLJIT_INLINE sljit_ins *process_extended_label(sljit_ins *code_ptr, struct sljit_extended_label *ext_label)774{775SLJIT_ASSERT(ext_label->label.u.index == SLJIT_LABEL_ALIGNED);776return (sljit_ins*)((sljit_uw)code_ptr & ~(ext_label->data));777}778779#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)780781static void reduce_code_size(struct sljit_compiler *compiler)782{783struct sljit_label *label;784struct sljit_jump *jump;785struct sljit_const *const_;786SLJIT_NEXT_DEFINE_TYPES;787sljit_uw total_size;788sljit_uw size_reduce = 0;789sljit_sw diff;790791label = compiler->labels;792jump = compiler->jumps;793const_ = compiler->consts;794SLJIT_NEXT_INIT_TYPES();795796while (1) {797SLJIT_GET_NEXT_MIN();798799if (next_min_addr == SLJIT_MAX_ADDRESS)800break;801802if (next_min_addr == next_label_size) {803label->size -= size_reduce;804805label = label->next;806next_label_size = SLJIT_GET_NEXT_SIZE(label);807}808809if (next_min_addr == next_const_addr) {810const_->addr -= size_reduce;811const_ = const_->next;812next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);813continue;814}815816if (next_min_addr != next_jump_addr)817continue;818819jump->addr -= size_reduce;820if (!(jump->flags & JUMP_MOV_ADDR)) {821total_size = JUMP_MAX_SIZE - 1;822823if (!(jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR))) {824/* Unit size: instruction. */825diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr - 2;826if (jump->u.label->size > jump->addr) {827SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr);828diff -= (sljit_sw)size_reduce;829}830831if (diff <= (0x01ffffff / SSIZE_OF(ins)) && diff >= (-0x02000000 / SSIZE_OF(ins)))832total_size = 1 - 1;833}834835size_reduce += JUMP_MAX_SIZE - 1 - total_size;836} else {837/* Real size minus 1. Unit size: instruction. */838total_size = 1;839840if (!(jump->flags & JUMP_ADDR)) {841diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr;842if (jump->u.label->size > jump->addr) {843SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr);844diff -= (sljit_sw)size_reduce;845}846847if (diff <= 0xff + 2 && diff >= -0xff + 2)848total_size = 0;849}850851size_reduce += 1 - total_size;852}853854jump->flags |= total_size << JUMP_SIZE_SHIFT;855jump = jump->next;856next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);857}858859compiler->size -= size_reduce;860}861862#endif /* SLJIT_CONFIG_ARM_V7 */863864SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)865{866struct sljit_memory_fragment *buf;867sljit_ins *code;868sljit_ins *code_ptr;869sljit_ins *buf_ptr;870sljit_ins *buf_end;871sljit_uw word_count;872SLJIT_NEXT_DEFINE_TYPES;873sljit_sw executable_offset;874sljit_uw addr;875sljit_sw diff;876#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)877sljit_uw cpool_size;878sljit_uw cpool_skip_alignment;879sljit_uw cpool_current_index;880sljit_ins *cpool_start_address;881sljit_ins *last_pc_patch;882struct future_patch *first_patch;883#endif884885struct sljit_label *label;886struct sljit_jump *jump;887struct sljit_const *const_;888889CHECK_ERROR_PTR();890CHECK_PTR(check_sljit_generate_code(compiler, options));891892/* Second code generation pass. */893#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)894compiler->size += (compiler->patches << 1);895if (compiler->cpool_fill > 0)896compiler->size += compiler->cpool_fill + CONST_POOL_ALIGNMENT - 1;897#else /* !SLJIT_CONFIG_ARM_V6 */898reduce_code_size(compiler);899#endif /* SLJIT_CONFIG_ARM_V6 */900code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset);901PTR_FAIL_WITH_EXEC_IF(code);902903reverse_buf(compiler);904buf = compiler->buf;905906#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)907cpool_size = 0;908cpool_skip_alignment = 0;909cpool_current_index = 0;910cpool_start_address = NULL;911first_patch = NULL;912last_pc_patch = code;913#endif /* SLJIT_CONFIG_ARM_V6 */914915code_ptr = code;916word_count = 0;917label = compiler->labels;918jump = compiler->jumps;919const_ = compiler->consts;920SLJIT_NEXT_INIT_TYPES();921SLJIT_GET_NEXT_MIN();922923do {924buf_ptr = (sljit_ins*)buf->memory;925buf_end = buf_ptr + (buf->used_size >> 2);926do {927#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)928if (cpool_size > 0) {929if (cpool_skip_alignment > 0) {930buf_ptr++;931cpool_skip_alignment--;932} else {933if (SLJIT_UNLIKELY(resolve_const_pool_index(compiler, &first_patch, cpool_current_index, cpool_start_address, buf_ptr))) {934SLJIT_FREE_EXEC(code, exec_allocator_data);935compiler->error = SLJIT_ERR_ALLOC_FAILED;936return NULL;937}938buf_ptr++;939if (++cpool_current_index >= cpool_size) {940SLJIT_ASSERT(!first_patch);941cpool_size = 0;942}943}944} else if ((*buf_ptr & 0xff000000) != PUSH_POOL) {945#endif /* SLJIT_CONFIG_ARM_V6 */946*code_ptr = *buf_ptr++;947if (next_min_addr == word_count) {948SLJIT_ASSERT(!label || label->size >= word_count);949SLJIT_ASSERT(!jump || jump->addr >= word_count);950SLJIT_ASSERT(!const_ || const_->addr >= word_count);951952if (next_min_addr == next_label_size) {953if (label->u.index >= SLJIT_LABEL_ALIGNED) {954code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);955*code_ptr = buf_ptr[-1];956}957958label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);959label->size = (sljit_uw)(code_ptr - code);960label = label->next;961next_label_size = SLJIT_GET_NEXT_SIZE(label);962}963964/* These structures are ordered by their address. */965if (next_min_addr == next_jump_addr) {966if (!(jump->flags & JUMP_MOV_ADDR)) {967#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)968if (detect_jump_type(jump, code_ptr, code, executable_offset))969code_ptr--;970jump->addr = (sljit_uw)code_ptr;971#else /* !SLJIT_CONFIG_ARM_V6 */972word_count += jump->flags >> JUMP_SIZE_SHIFT;973if (!detect_jump_type(jump, code_ptr, code, executable_offset)) {974code_ptr[2] = code_ptr[0];975addr = ((code_ptr[0] & 0xf) << 12);976code_ptr[0] = MOVW | addr;977code_ptr[1] = MOVT | addr;978code_ptr += 2;979}980SLJIT_ASSERT((sljit_uw)code_ptr - jump->addr <= (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins));981#endif /* SLJIT_CONFIG_ARM_V6 */982} else {983#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)984word_count += jump->flags >> JUMP_SIZE_SHIFT;985#endif /* SLJIT_CONFIG_ARM_V7 */986addr = (sljit_uw)code_ptr;987code_ptr += mov_addr_get_length(jump, code_ptr, code, executable_offset);988jump->addr = addr;989}990jump = jump->next;991next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);992} else if (next_min_addr == next_const_addr) {993const_->addr = (sljit_uw)code_ptr;994const_ = const_->next;995next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);996}997998SLJIT_GET_NEXT_MIN();999}1000code_ptr++;1001#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)1002} else {1003/* Fortunately, no need to shift. */1004cpool_size = *buf_ptr++ & ~PUSH_POOL;1005SLJIT_ASSERT(cpool_size > 0);1006cpool_start_address = ALIGN_INSTRUCTION(code_ptr + 1);1007cpool_current_index = patch_pc_relative_loads(last_pc_patch, code_ptr, cpool_start_address, cpool_size);1008if (cpool_current_index > 0) {1009/* Unconditional branch. */1010*code_ptr = B | (((sljit_ins)(cpool_start_address - code_ptr) + cpool_current_index - 2) & ~PUSH_POOL);1011code_ptr = (sljit_ins*)(cpool_start_address + cpool_current_index);1012}1013cpool_skip_alignment = CONST_POOL_ALIGNMENT - 1;1014cpool_current_index = 0;1015last_pc_patch = code_ptr;1016}1017#endif /* SLJIT_CONFIG_ARM_V6 */1018word_count++;1019} while (buf_ptr < buf_end);1020buf = buf->next;1021} while (buf);10221023if (label && label->size == word_count) {1024if (label->u.index >= SLJIT_LABEL_ALIGNED)1025code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);10261027label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);1028label->size = (sljit_uw)(code_ptr - code);1029label = label->next;1030}10311032SLJIT_ASSERT(!label);1033SLJIT_ASSERT(!jump);1034SLJIT_ASSERT(!const_);10351036#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)1037SLJIT_ASSERT(cpool_size == 0);1038if (compiler->cpool_fill > 0) {1039cpool_start_address = ALIGN_INSTRUCTION(code_ptr);1040cpool_current_index = patch_pc_relative_loads(last_pc_patch, code_ptr, cpool_start_address, compiler->cpool_fill);1041if (cpool_current_index > 0)1042code_ptr = (sljit_ins*)(cpool_start_address + cpool_current_index);10431044buf_ptr = compiler->cpool;1045buf_end = buf_ptr + compiler->cpool_fill;1046cpool_current_index = 0;1047while (buf_ptr < buf_end) {1048if (SLJIT_UNLIKELY(resolve_const_pool_index(compiler, &first_patch, cpool_current_index, cpool_start_address, buf_ptr))) {1049SLJIT_FREE_EXEC(code, exec_allocator_data);1050compiler->error = SLJIT_ERR_ALLOC_FAILED;1051return NULL;1052}1053buf_ptr++;1054cpool_current_index++;1055}1056SLJIT_ASSERT(!first_patch);1057}1058#endif10591060jump = compiler->jumps;1061while (jump) {1062addr = (jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr;1063buf_ptr = (sljit_ins*)jump->addr;10641065if (jump->flags & JUMP_MOV_ADDR) {1066#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)1067SLJIT_ASSERT((buf_ptr[0] & (sljit_ins)0xffff0000) == 0xe59f0000);1068#else /* !SLJIT_CONFIG_ARM_V6 */1069SLJIT_ASSERT((buf_ptr[0] & ~(sljit_ins)0xf000) == 0);1070#endif /* SLJIT_CONFIG_ARM_V6 */10711072if (jump->flags & PATCH_B) {1073SLJIT_ASSERT((((sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset)) & 0x3) == 0);1074diff = ((sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset)) >> 2;10751076SLJIT_ASSERT(diff <= 0xff && diff >= -0xff);10771078addr = ADD;1079if (diff < 0) {1080diff = -diff;1081addr = SUB;1082}10831084buf_ptr[0] = addr | (buf_ptr[0] & 0xf000) | RN(TMP_PC) | (1 << 25) | (0xf << 8) | (sljit_ins)(diff & 0xff);1085} else {1086#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)1087buf_ptr[((buf_ptr[0] & 0xfff) >> 2) + 2] = addr;1088#else /* !SLJIT_CONFIG_ARM_V6 */1089buf_ptr[1] = MOVT | buf_ptr[0] | ((addr >> 12) & 0xf0000) | ((addr >> 16) & 0xfff);1090buf_ptr[0] = MOVW | buf_ptr[0] | ((addr << 4) & 0xf0000) | (addr & 0xfff);1091#endif /* SLJIT_CONFIG_ARM_V6 */1092}1093} else if (jump->flags & PATCH_B) {1094diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset);1095SLJIT_ASSERT(diff <= 0x01ffffff && diff >= -0x02000000);1096*buf_ptr |= (diff >> 2) & 0x00ffffff;1097} else {1098#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)1099if (jump->flags & IS_BL)1100buf_ptr--;11011102if (jump->flags & SLJIT_REWRITABLE_JUMP) {1103jump->addr = (sljit_uw)code_ptr;1104code_ptr[0] = (sljit_ins)buf_ptr;1105code_ptr[1] = *buf_ptr;1106set_jump_addr((sljit_uw)code_ptr, executable_offset, addr, 0);1107code_ptr += 2;1108} else {1109if (*buf_ptr & (1 << 23))1110buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2;1111else1112buf_ptr += 1;1113*buf_ptr = addr;1114}1115#else /* !SLJIT_CONFIG_ARM_V6 */1116set_jump_addr((sljit_uw)buf_ptr, executable_offset, addr, 0);1117#endif /* SLJIT_CONFIG_ARM_V6 */1118}11191120jump = jump->next;1121}11221123#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)1124const_ = compiler->consts;1125while (const_) {1126buf_ptr = (sljit_ins*)const_->addr;11271128/* Note: MVN = (MOV ^ 0x400000) */1129SLJIT_ASSERT((*buf_ptr & 0xfdb00000) == MOV || (*buf_ptr & 0xfd100000) == LDR);11301131if ((*buf_ptr & 0x4000000) != 0) {1132const_->addr = (sljit_uw)code_ptr;11331134code_ptr[0] = (sljit_ins)buf_ptr;1135code_ptr[1] = *buf_ptr;1136if (*buf_ptr & (1 << 23))1137buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2;1138else1139buf_ptr += 1;1140/* Set the value again (can be a simple constant). */1141set_const_value((sljit_uw)code_ptr, executable_offset, *buf_ptr, 0);1142code_ptr += 2;1143}11441145const_ = const_->next;1146}1147#endif /* SLJIT_CONFIG_ARM_V6 */11481149SLJIT_ASSERT(code_ptr - code <= (sljit_s32)compiler->size);11501151compiler->error = SLJIT_ERR_COMPILED;1152compiler->executable_offset = executable_offset;1153compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_uw);11541155code = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);1156code_ptr = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);11571158SLJIT_CACHE_FLUSH(code, code_ptr);1159SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);1160return code;1161}11621163SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)1164{1165switch (feature_type) {1166case SLJIT_HAS_FPU:1167case SLJIT_HAS_F64_AS_F32_PAIR:1168#ifdef SLJIT_IS_FPU_AVAILABLE1169return (SLJIT_IS_FPU_AVAILABLE) != 0;1170#else1171/* Available by default. */1172return 1;1173#endif /* SLJIT_IS_FPU_AVAILABLE */1174case SLJIT_HAS_SIMD:1175#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)1176return 0;1177#else1178#ifdef SLJIT_IS_FPU_AVAILABLE1179return (SLJIT_IS_FPU_AVAILABLE) != 0;1180#else1181/* Available by default. */1182return 1;1183#endif /* SLJIT_IS_FPU_AVAILABLE */1184#endif /* SLJIT_CONFIG_ARM_V6 */11851186case SLJIT_SIMD_REGS_ARE_PAIRS:1187case SLJIT_HAS_CLZ:1188case SLJIT_HAS_ROT:1189case SLJIT_HAS_CMOV:1190case SLJIT_HAS_REV:1191case SLJIT_HAS_PREFETCH:1192case SLJIT_HAS_COPY_F32:1193case SLJIT_HAS_COPY_F64:1194case SLJIT_HAS_ATOMIC:1195#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)1196case SLJIT_HAS_MEMORY_BARRIER:1197#endif /* SLJIT_CONFIG_ARM_V7 */1198return 1;11991200case SLJIT_HAS_CTZ:1201#if defined(SLJIT_CONFIG_ARM_V6) && SLJIT_CONFIG_ARM_V61202return 2;1203#else1204return 1;1205#endif /* SLJIT_CONFIG_ARM_V6 */12061207default:1208return 0;1209}1210}12111212/* --------------------------------------------------------------------- */1213/* Entry, exit */1214/* --------------------------------------------------------------------- */12151216/* Creates an index in data_transfer_insts array. */1217#define WORD_SIZE 0x001218#define BYTE_SIZE 0x011219#define HALF_SIZE 0x021220#define PRELOAD 0x031221#define SIGNED 0x041222#define LOAD_DATA 0x0812231224/* Flag bits for emit_op. */1225#define ALLOW_IMM 0x101226#define ALLOW_INV_IMM 0x201227#define ALLOW_ANY_IMM (ALLOW_IMM | ALLOW_INV_IMM)1228#define ALLOW_NEG_IMM 0x401229#define ALLOW_DOUBLE_IMM 0x8012301231/* s/l - store/load (1 bit)1232u/s - signed/unsigned (1 bit)1233w/b/h/N - word/byte/half/NOT allowed (2 bit)1234Storing signed and unsigned values are the same operations. */12351236static const sljit_ins data_transfer_insts[16] = {1237/* s u w */ 0xe5000000 /* str */,1238/* s u b */ 0xe5400000 /* strb */,1239/* s u h */ 0xe10000b0 /* strh */,1240/* s u N */ 0x00000000 /* not allowed */,1241/* s s w */ 0xe5000000 /* str */,1242/* s s b */ 0xe5400000 /* strb */,1243/* s s h */ 0xe10000b0 /* strh */,1244/* s s N */ 0x00000000 /* not allowed */,12451246/* l u w */ 0xe5100000 /* ldr */,1247/* l u b */ 0xe5500000 /* ldrb */,1248/* l u h */ 0xe11000b0 /* ldrh */,1249/* l u p */ 0xf5500000 /* preload */,1250/* l s w */ 0xe5100000 /* ldr */,1251/* l s b */ 0xe11000d0 /* ldrsb */,1252/* l s h */ 0xe11000f0 /* ldrsh */,1253/* l s N */ 0x00000000 /* not allowed */,1254};12551256#define EMIT_DATA_TRANSFER(type, add, target_reg, base_reg, arg) \1257(data_transfer_insts[(type) & 0xf] | ((add) << 23) | RD(target_reg) | RN(base_reg) | (sljit_ins)(arg))12581259/* Normal ldr/str instruction.1260Type2: ldrsb, ldrh, ldrsh */1261#define IS_TYPE1_TRANSFER(type) \1262(data_transfer_insts[(type) & 0xf] & 0x04000000)1263#define TYPE2_TRANSFER_IMM(imm) \1264(((imm) & 0xf) | (((imm) & 0xf0) << 4) | (1 << 22))12651266#define EMIT_FPU_OPERATION(opcode, mode, dst, src1, src2) \1267((sljit_ins)(opcode) | (sljit_ins)(mode) | VD(dst) | VM(src1) | VN(src2))12681269/* Flags for emit_op: */1270/* Arguments are swapped. */1271#define ARGS_SWAPPED 0x011272/* Inverted immediate. */1273#define INV_IMM 0x021274/* Source and destination is register. */1275#define REGISTER_OP 0x041276/* Unused return value. */1277#define UNUSED_RETURN 0x081278/* SET_FLAGS must be (1 << 20) as it is also the value of S bit (can be used for optimization). */1279#define SET_FLAGS (1 << 20)1280/* dst: reg1281src1: reg1282src2: reg or imm (if allowed)1283SRC2_IMM must be (1 << 25) as it is also the value of I bit (can be used for optimization). */1284#define SRC2_IMM (1 << 25)12851286static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 inp_flags,1287sljit_s32 dst, sljit_sw dstw,1288sljit_s32 src1, sljit_sw src1w,1289sljit_s32 src2, sljit_sw src2w);12901291SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,1292sljit_s32 options, sljit_s32 arg_types,1293sljit_s32 scratches, sljit_s32 saveds, sljit_s32 local_size)1294{1295sljit_s32 fscratches;1296sljit_s32 fsaveds;1297sljit_uw imm, offset;1298sljit_s32 i, tmp, size, word_arg_count;1299sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options);1300#ifdef __SOFTFP__1301sljit_u32 float_arg_count;1302#else1303sljit_u32 old_offset, f32_offset;1304sljit_u32 remap[3];1305sljit_u32 *remap_ptr = remap;1306#endif13071308CHECK_ERROR();1309CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, local_size));1310set_emit_enter(compiler, options, arg_types, scratches, saveds, local_size);13111312scratches = ENTER_GET_REGS(scratches);1313saveds = ENTER_GET_REGS(saveds);1314fscratches = compiler->fscratches;1315fsaveds = compiler->fsaveds;13161317imm = 0;1318tmp = SLJIT_S0 - saveds;1319for (i = SLJIT_S0 - saved_arg_count; i > tmp; i--)1320imm |= (sljit_uw)1 << reg_map[i];13211322for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--)1323imm |= (sljit_uw)1 << reg_map[i];13241325SLJIT_ASSERT(reg_map[TMP_REG2] == 14);13261327/* Push saved and temporary registers1328multiple registers: stmdb sp!, {..., lr}1329single register: str reg, [sp, #-4]! */1330if (imm != 0)1331FAIL_IF(push_inst(compiler, PUSH | (1 << 14) | imm));1332else1333FAIL_IF(push_inst(compiler, 0xe52d0004 | RD(TMP_REG2)));13341335/* Stack must be aligned to 8 bytes: */1336size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 1);13371338if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {1339if ((size & SSIZE_OF(sw)) != 0) {1340FAIL_IF(push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | SRC2_IMM | sizeof(sljit_sw)));1341size += SSIZE_OF(sw);1342}13431344if (fsaveds + fscratches >= SLJIT_NUMBER_OF_FLOAT_REGISTERS) {1345FAIL_IF(push_inst(compiler, VPUSH | VD(SLJIT_FS0) | ((sljit_ins)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1)));1346} else {1347if (fsaveds > 0)1348FAIL_IF(push_inst(compiler, VPUSH | VD(SLJIT_FS0) | ((sljit_ins)fsaveds << 1)));1349if (fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG)1350FAIL_IF(push_inst(compiler, VPUSH | VD(fscratches) | ((sljit_ins)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1)));1351}1352}13531354local_size = ((size + local_size + 0x7) & ~0x7) - size;1355compiler->local_size = local_size;13561357if (options & SLJIT_ENTER_REG_ARG)1358arg_types = 0;13591360arg_types >>= SLJIT_ARG_SHIFT;1361word_arg_count = 0;1362saved_arg_count = 0;1363#ifdef __SOFTFP__1364SLJIT_COMPILE_ASSERT(SLJIT_FR0 == 1, float_register_index_start);13651366offset = 0;1367float_arg_count = 0;13681369while (arg_types) {1370switch (arg_types & SLJIT_ARG_MASK) {1371case SLJIT_ARG_TYPE_F64:1372if (offset & 0x7)1373offset += sizeof(sljit_sw);13741375if (offset < 4 * sizeof(sljit_sw))1376FAIL_IF(push_inst(compiler, VMOV2 | (offset << 10) | ((offset + sizeof(sljit_sw)) << 14) | float_arg_count));1377else1378FAIL_IF(push_inst(compiler, VLDR_F32 | 0x800100 | RN(SLJIT_SP)1379| (float_arg_count << 12) | ((offset + (sljit_ins)size - 4 * sizeof(sljit_sw)) >> 2)));1380float_arg_count++;1381offset += sizeof(sljit_f64) - sizeof(sljit_sw);1382break;1383case SLJIT_ARG_TYPE_F32:1384if (offset < 4 * sizeof(sljit_sw))1385FAIL_IF(push_inst(compiler, VMOV | (float_arg_count << 16) | (offset << 10)));1386else1387FAIL_IF(push_inst(compiler, VLDR_F32 | 0x800000 | RN(SLJIT_SP)1388| (float_arg_count << 12) | ((offset + (sljit_ins)size - 4 * sizeof(sljit_sw)) >> 2)));1389float_arg_count++;1390break;1391default:1392word_arg_count++;13931394if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) {1395tmp = SLJIT_S0 - saved_arg_count;1396saved_arg_count++;1397} else if (word_arg_count - 1 != (sljit_s32)(offset >> 2))1398tmp = word_arg_count;1399else1400break;14011402if (offset < 4 * sizeof(sljit_sw))1403FAIL_IF(push_inst(compiler, MOV | RD(tmp) | (offset >> 2)));1404else1405FAIL_IF(push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(tmp) | (offset + (sljit_ins)size - 4 * sizeof(sljit_sw))));1406break;1407}14081409offset += sizeof(sljit_sw);1410arg_types >>= SLJIT_ARG_SHIFT;1411}14121413compiler->args_size = offset;1414#else1415offset = SLJIT_FR0;1416old_offset = SLJIT_FR0;1417f32_offset = 0;14181419while (arg_types) {1420switch (arg_types & SLJIT_ARG_MASK) {1421case SLJIT_ARG_TYPE_F64:1422if (offset != old_offset)1423*remap_ptr++ = EMIT_FPU_OPERATION(VMOV_F32, SLJIT_32, offset, old_offset, 0);1424old_offset++;1425offset++;1426break;1427case SLJIT_ARG_TYPE_F32:1428if (f32_offset != 0) {1429*remap_ptr++ = EMIT_FPU_OPERATION(VMOV_F32, 0x20, offset, f32_offset, 0);1430f32_offset = 0;1431} else {1432if (offset != old_offset)1433*remap_ptr++ = EMIT_FPU_OPERATION(VMOV_F32, 0, offset, old_offset, 0);1434f32_offset = old_offset;1435old_offset++;1436}1437offset++;1438break;1439default:1440if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) {1441FAIL_IF(push_inst(compiler, MOV | RD(SLJIT_S0 - saved_arg_count) | RM(SLJIT_R0 + word_arg_count)));1442saved_arg_count++;1443}14441445word_arg_count++;1446break;1447}1448arg_types >>= SLJIT_ARG_SHIFT;1449}14501451SLJIT_ASSERT((sljit_uw)(remap_ptr - remap) <= sizeof(remap));14521453while (remap_ptr > remap)1454FAIL_IF(push_inst(compiler, *(--remap_ptr)));1455#endif14561457if (local_size > 0)1458FAIL_IF(emit_op(compiler, SLJIT_SUB, ALLOW_IMM | ALLOW_DOUBLE_IMM, SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size));14591460return SLJIT_SUCCESS;1461}14621463SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,1464sljit_s32 options, sljit_s32 arg_types,1465sljit_s32 scratches, sljit_s32 saveds, sljit_s32 local_size)1466{1467sljit_s32 fscratches;1468sljit_s32 fsaveds;1469sljit_s32 size;14701471CHECK_ERROR();1472CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, local_size));1473set_emit_enter(compiler, options, arg_types, scratches, saveds, local_size);14741475scratches = ENTER_GET_REGS(scratches);1476saveds = ENTER_GET_REGS(saveds);1477fscratches = compiler->fscratches;1478fsaveds = compiler->fsaveds;1479size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 1);14801481/* Doubles are saved, so alignment is unaffected. */1482if ((size & SSIZE_OF(sw)) != 0 && (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG))1483size += SSIZE_OF(sw);14841485compiler->local_size = ((size + local_size + 0x7) & ~0x7) - size;1486return SLJIT_SUCCESS;1487}14881489static sljit_s32 emit_add_sp(struct sljit_compiler *compiler, sljit_uw imm)1490{1491sljit_uw imm2 = get_imm(imm);14921493if (imm2 == 0)1494return emit_op(compiler, SLJIT_ADD, ALLOW_IMM | ALLOW_DOUBLE_IMM, SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, (sljit_sw)imm);14951496return push_inst(compiler, ADD | RD(SLJIT_SP) | RN(SLJIT_SP) | imm2);1497}14981499static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 frame_size)1500{1501sljit_s32 local_size, fscratches, fsaveds, i, tmp;1502sljit_s32 restored_reg = 0;1503sljit_s32 lr_dst = TMP_PC;1504sljit_uw reg_list = 0;15051506SLJIT_ASSERT(reg_map[TMP_REG2] == 14 && frame_size <= 128);15071508local_size = compiler->local_size;1509fscratches = compiler->fscratches;1510fsaveds = compiler->fsaveds;15111512if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {1513if (local_size > 0)1514FAIL_IF(emit_add_sp(compiler, (sljit_uw)local_size));15151516if (fsaveds + fscratches >= SLJIT_NUMBER_OF_FLOAT_REGISTERS) {1517FAIL_IF(push_inst(compiler, VPOP | VD(SLJIT_FS0) | ((sljit_ins)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1)));1518} else {1519if (fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG)1520FAIL_IF(push_inst(compiler, VPOP | VD(fscratches) | ((sljit_ins)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1)));1521if (fsaveds > 0)1522FAIL_IF(push_inst(compiler, VPOP | VD(SLJIT_FS0) | ((sljit_ins)fsaveds << 1)));1523}15241525local_size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1) & 0x7;1526}15271528if (frame_size < 0) {1529lr_dst = TMP_REG2;1530frame_size = 0;1531} else if (frame_size > 0) {1532SLJIT_ASSERT(frame_size == 1 || (frame_size & 0x7) == 0);1533lr_dst = 0;1534frame_size &= ~0x7;1535}15361537if (lr_dst != 0)1538reg_list |= (sljit_uw)1 << reg_map[lr_dst];15391540tmp = SLJIT_S0 - compiler->saveds;1541i = SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options);1542if (tmp < i) {1543restored_reg = i;1544do {1545reg_list |= (sljit_uw)1 << reg_map[i];1546} while (--i > tmp);1547}15481549i = compiler->scratches;1550if (i >= SLJIT_FIRST_SAVED_REG) {1551restored_reg = i;1552do {1553reg_list |= (sljit_uw)1 << reg_map[i];1554} while (--i >= SLJIT_FIRST_SAVED_REG);1555}15561557if (lr_dst == TMP_REG2 && reg_list == 0) {1558restored_reg = TMP_REG2;1559lr_dst = 0;1560}15611562if (lr_dst == 0 && (reg_list & (reg_list - 1)) == 0) {1563/* The local_size does not include the saved registers. */1564tmp = 0;1565if (reg_list != 0) {1566tmp = 2;1567if (local_size <= 0xfff) {1568if (local_size == 0) {1569SLJIT_ASSERT(restored_reg != TMP_REG2);1570if (frame_size == 0)1571return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(restored_reg) | 0x800008);1572if (frame_size > 2 * SSIZE_OF(sw))1573return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(restored_reg) | (sljit_ins)(frame_size - (2 * SSIZE_OF(sw))));1574}15751576FAIL_IF(push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(restored_reg) | (sljit_ins)local_size));1577tmp = 1;1578} else if (frame_size == 0) {1579frame_size = (restored_reg == TMP_REG2) ? SSIZE_OF(sw) : 2 * SSIZE_OF(sw);1580tmp = 3;1581}15821583/* Place for the saved register. */1584if (restored_reg != TMP_REG2)1585local_size += SSIZE_OF(sw);1586}15871588/* Place for the lr register. */1589local_size += SSIZE_OF(sw);15901591if (frame_size > local_size)1592FAIL_IF(push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 25) | (sljit_ins)(frame_size - local_size)));1593else if (frame_size < local_size)1594FAIL_IF(emit_add_sp(compiler, (sljit_uw)(local_size - frame_size)));15951596if (tmp <= 1)1597return SLJIT_SUCCESS;15981599if (tmp == 2) {1600frame_size -= SSIZE_OF(sw);1601if (restored_reg != TMP_REG2)1602frame_size -= SSIZE_OF(sw);16031604return push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(restored_reg) | (sljit_ins)frame_size);1605}16061607tmp = (restored_reg == TMP_REG2) ? 0x800004 : 0x800008;1608return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(restored_reg) | (sljit_ins)tmp);1609}16101611if (local_size > 0)1612FAIL_IF(emit_add_sp(compiler, (sljit_uw)local_size));16131614/* Pop saved and temporary registers1615multiple registers: ldmia sp!, {...}1616single register: ldr reg, [sp], #4 */1617if ((reg_list & (reg_list - 1)) == 0) {1618SLJIT_ASSERT(lr_dst != 0);1619SLJIT_ASSERT(reg_list == (sljit_uw)1 << reg_map[lr_dst]);16201621return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(lr_dst) | 0x800004);1622}16231624FAIL_IF(push_inst(compiler, POP | reg_list));16251626if (frame_size > 0)1627return push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 25) | ((sljit_ins)frame_size - sizeof(sljit_sw)));16281629if (lr_dst != 0)1630return SLJIT_SUCCESS;16311632return push_inst(compiler, ADD | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 25) | sizeof(sljit_sw));1633}16341635SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler)1636{1637CHECK_ERROR();1638CHECK(check_sljit_emit_return_void(compiler));16391640return emit_stack_frame_release(compiler, 0);1641}16421643SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler,1644sljit_s32 src, sljit_sw srcw)1645{1646CHECK_ERROR();1647CHECK(check_sljit_emit_return_to(compiler, src, srcw));16481649if (src & SLJIT_MEM) {1650FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));1651src = TMP_REG1;1652srcw = 0;1653} else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) {1654FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | RM(src)));1655src = TMP_REG1;1656srcw = 0;1657}16581659FAIL_IF(emit_stack_frame_release(compiler, 1));16601661SLJIT_SKIP_CHECKS(compiler);1662return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw);1663}16641665/* --------------------------------------------------------------------- */1666/* Operators */1667/* --------------------------------------------------------------------- */16681669static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,1670sljit_uw dst, sljit_uw src1, sljit_uw src2)1671{1672sljit_s32 reg, is_masked;1673sljit_uw shift_type;16741675switch (op) {1676case SLJIT_MOV:1677SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));1678if (dst != src2) {1679if (src2 & SRC2_IMM) {1680return push_inst(compiler, ((flags & INV_IMM) ? MVN : MOV) | RD(dst) | src2);1681}1682return push_inst(compiler, MOV | RD(dst) | RM(src2));1683}1684return SLJIT_SUCCESS;16851686case SLJIT_MOV_U8:1687case SLJIT_MOV_S8:1688SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));1689if (flags & REGISTER_OP)1690return push_inst(compiler, (op == SLJIT_MOV_U8 ? UXTB : SXTB) | RD(dst) | RM(src2));16911692if (dst != src2) {1693SLJIT_ASSERT(src2 & SRC2_IMM);1694return push_inst(compiler, ((flags & INV_IMM) ? MVN : MOV) | RD(dst) | src2);1695}1696return SLJIT_SUCCESS;16971698case SLJIT_MOV_U16:1699case SLJIT_MOV_S16:1700SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));1701if (flags & REGISTER_OP)1702return push_inst(compiler, (op == SLJIT_MOV_U16 ? UXTH : SXTH) | RD(dst) | RM(src2));17031704if (dst != src2) {1705SLJIT_ASSERT(src2 & SRC2_IMM);1706return push_inst(compiler, ((flags & INV_IMM) ? MVN : MOV) | RD(dst) | src2);1707}1708return SLJIT_SUCCESS;17091710case SLJIT_CLZ:1711SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM));1712FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(src2)));1713return SLJIT_SUCCESS;17141715case SLJIT_CTZ:1716SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM));1717SLJIT_ASSERT(src1 == TMP_REG1 && src2 != TMP_REG2 && !(flags & ARGS_SWAPPED));1718#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)1719FAIL_IF(push_inst(compiler, RSB | SRC2_IMM | RD(TMP_REG2) | RN(src2) | 0));1720FAIL_IF(push_inst(compiler, AND | RD(TMP_REG1) | RN(src2) | RM(TMP_REG2)));1721FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(TMP_REG1)));1722FAIL_IF(push_inst(compiler, CMP | SET_FLAGS | SRC2_IMM | RN(dst) | 32));1723return push_inst(compiler, (EOR ^ 0xf0000000) | SRC2_IMM | RD(dst) | RN(dst) | 0x1f);1724#else /* !SLJIT_CONFIG_ARM_V6 */1725FAIL_IF(push_inst(compiler, RBIT | RD(dst) | RM(src2)));1726return push_inst(compiler, CLZ | RD(dst) | RM(dst));1727#endif /* SLJIT_CONFIG_ARM_V6 */17281729case SLJIT_REV:1730case SLJIT_REV_U32:1731case SLJIT_REV_S32:1732SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));1733return push_inst(compiler, REV | RD(dst) | RM(src2));17341735case SLJIT_REV_U16:1736case SLJIT_REV_S16:1737SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));1738FAIL_IF(push_inst(compiler, REV16 | RD(dst) | RM(src2)));1739if (!(flags & REGISTER_OP))1740return SLJIT_SUCCESS;1741return push_inst(compiler, (op == SLJIT_REV_U16 ? UXTH : SXTH) | RD(dst) | RM(dst));1742case SLJIT_ADD:1743SLJIT_ASSERT(!(flags & INV_IMM));17441745if ((flags & (UNUSED_RETURN | ARGS_SWAPPED)) == UNUSED_RETURN)1746return push_inst(compiler, CMN | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));1747return push_inst(compiler, ADD | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));17481749case SLJIT_ADDC:1750SLJIT_ASSERT(!(flags & INV_IMM));1751return push_inst(compiler, ADC | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));17521753case SLJIT_SUB:1754SLJIT_ASSERT(!(flags & INV_IMM));17551756if ((flags & (UNUSED_RETURN | ARGS_SWAPPED)) == UNUSED_RETURN)1757return push_inst(compiler, CMP | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));17581759return push_inst(compiler, (!(flags & ARGS_SWAPPED) ? SUB : RSB) | (flags & SET_FLAGS)1760| RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));17611762case SLJIT_SUBC:1763SLJIT_ASSERT(!(flags & INV_IMM));1764return push_inst(compiler, (!(flags & ARGS_SWAPPED) ? SBC : RSC) | (flags & SET_FLAGS)1765| RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));17661767case SLJIT_MUL:1768SLJIT_ASSERT(!(flags & INV_IMM));1769SLJIT_ASSERT(!(src2 & SRC2_IMM));1770compiler->status_flags_state = 0;17711772if (!(flags & SET_FLAGS))1773return push_inst(compiler, MUL | RN(dst) | RM8(src2) | RM(src1));17741775reg = dst == TMP_REG1 ? TMP_REG2 : TMP_REG1;1776FAIL_IF(push_inst(compiler, SMULL | RN(reg) | RD(dst) | RM8(src2) | RM(src1)));17771778/* cmp TMP_REG1, dst asr #31. */1779return push_inst(compiler, CMP | SET_FLAGS | RN(reg) | RM(dst) | 0xfc0);17801781case SLJIT_AND:1782if ((flags & (UNUSED_RETURN | INV_IMM)) == UNUSED_RETURN)1783return push_inst(compiler, TST | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));1784return push_inst(compiler, (!(flags & INV_IMM) ? AND : BIC) | (flags & SET_FLAGS)1785| RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));17861787case SLJIT_OR:1788SLJIT_ASSERT(!(flags & INV_IMM));1789return push_inst(compiler, ORR | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));17901791case SLJIT_XOR:1792if (flags & INV_IMM) {1793SLJIT_ASSERT(src2 == SRC2_IMM);1794return push_inst(compiler, MVN | (flags & SET_FLAGS) | RD(dst) | RM(src1));1795}1796return push_inst(compiler, EOR | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));17971798case SLJIT_SHL:1799case SLJIT_MSHL:1800shift_type = 0;1801is_masked = op == SLJIT_MSHL;1802break;18031804case SLJIT_LSHR:1805case SLJIT_MLSHR:1806shift_type = 1;1807is_masked = op == SLJIT_MLSHR;1808break;18091810case SLJIT_ASHR:1811case SLJIT_MASHR:1812shift_type = 2;1813is_masked = op == SLJIT_MASHR;1814break;18151816case SLJIT_ROTL:1817if (compiler->shift_imm == 0x20) {1818FAIL_IF(push_inst(compiler, RSB | SRC2_IMM | RD(TMP_REG2) | RN(src2) | 0));1819src2 = TMP_REG2;1820} else1821compiler->shift_imm = (sljit_uw)(-(sljit_sw)compiler->shift_imm) & 0x1f;1822SLJIT_FALLTHROUGH18231824case SLJIT_ROTR:1825shift_type = 3;1826is_masked = 0;1827break;18281829case SLJIT_MULADD:1830return push_inst(compiler, MLA | RN(dst) | RD(dst) | RM8(src2) | RM(src1));18311832default:1833SLJIT_UNREACHABLE();1834return SLJIT_SUCCESS;1835}18361837SLJIT_ASSERT(!(flags & ARGS_SWAPPED) && !(flags & INV_IMM) && !(src2 & SRC2_IMM));18381839if (compiler->shift_imm != 0x20) {1840SLJIT_ASSERT(src1 == TMP_REG1);18411842if (compiler->shift_imm != 0)1843return push_inst(compiler, MOV | (flags & SET_FLAGS) |1844RD(dst) | (compiler->shift_imm << 7) | (shift_type << 5) | RM(src2));1845return push_inst(compiler, MOV | (flags & SET_FLAGS) | RD(dst) | RM(src2));1846}18471848SLJIT_ASSERT(src1 != TMP_REG2);18491850if (is_masked) {1851FAIL_IF(push_inst(compiler, AND | RD(TMP_REG2) | RN(src2) | SRC2_IMM | 0x1f));1852src2 = TMP_REG2;1853}18541855return push_inst(compiler, MOV | (flags & SET_FLAGS) | RD(dst)1856| RM8(src2) | (sljit_ins)(shift_type << 5) | 0x10 | RM(src1));1857}18581859#undef EMIT_SHIFT_INS_AND_RETURN18601861/* Tests whether the immediate can be stored in the 12 bit imm field.1862Returns with 0 if not possible. */1863static sljit_uw get_imm(sljit_uw imm)1864{1865sljit_u32 rol;18661867if (imm <= 0xff)1868return SRC2_IMM | imm;18691870if (!(imm & 0xff000000)) {1871imm <<= 8;1872rol = 8;1873} else {1874imm = (imm << 24) | (imm >> 8);1875rol = 0;1876}18771878if (!(imm & 0xff000000)) {1879imm <<= 8;1880rol += 4;1881}18821883if (!(imm & 0xf0000000)) {1884imm <<= 4;1885rol += 2;1886}18871888if (!(imm & 0xc0000000)) {1889imm <<= 2;1890rol += 1;1891}18921893if (!(imm & 0x00ffffff))1894return SRC2_IMM | (imm >> 24) | (rol << 8);1895return 0;1896}18971898static sljit_uw compute_imm(sljit_uw imm, sljit_uw* imm2)1899{1900sljit_uw mask;1901sljit_uw imm1;1902sljit_uw rol;19031904/* Step1: Search a zero byte (8 continous zero bit). */1905mask = 0xff000000;1906rol = 8;1907while (1) {1908if (!(imm & mask)) {1909/* Rol imm by rol. */1910imm = (imm << rol) | (imm >> (32 - rol));1911/* Calculate arm rol. */1912rol = 4 + (rol >> 1);1913break;1914}19151916rol += 2;1917mask >>= 2;1918if (mask & 0x3) {1919/* rol by 8. */1920imm = (imm << 8) | (imm >> 24);1921mask = 0xff00;1922rol = 24;1923while (1) {1924if (!(imm & mask)) {1925/* Rol imm by rol. */1926imm = (imm << rol) | (imm >> (32 - rol));1927/* Calculate arm rol. */1928rol = (rol >> 1) - 8;1929break;1930}1931rol += 2;1932mask >>= 2;1933if (mask & 0x3)1934return 0;1935}1936break;1937}1938}19391940/* The low 8 bit must be zero. */1941SLJIT_ASSERT(!(imm & 0xff));19421943if (!(imm & 0xff000000)) {1944imm1 = SRC2_IMM | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8);1945*imm2 = SRC2_IMM | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8);1946} else if (imm & 0xc0000000) {1947imm1 = SRC2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);1948imm <<= 8;1949rol += 4;19501951if (!(imm & 0xff000000)) {1952imm <<= 8;1953rol += 4;1954}19551956if (!(imm & 0xf0000000)) {1957imm <<= 4;1958rol += 2;1959}19601961if (!(imm & 0xc0000000)) {1962imm <<= 2;1963rol += 1;1964}19651966if (!(imm & 0x00ffffff))1967*imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8);1968else1969return 0;1970} else {1971if (!(imm & 0xf0000000)) {1972imm <<= 4;1973rol += 2;1974}19751976if (!(imm & 0xc0000000)) {1977imm <<= 2;1978rol += 1;1979}19801981imm1 = SRC2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);1982imm <<= 8;1983rol += 4;19841985if (!(imm & 0xf0000000)) {1986imm <<= 4;1987rol += 2;1988}19891990if (!(imm & 0xc0000000)) {1991imm <<= 2;1992rol += 1;1993}19941995if (!(imm & 0x00ffffff))1996*imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8);1997else1998return 0;1999}20002001return imm1;2002}20032004static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm)2005{2006sljit_uw tmp;2007#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)2008sljit_uw imm1, imm2;2009#else /* !SLJIT_CONFIG_ARM_V6 */2010if (!(imm & ~(sljit_uw)0xffff))2011return push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff));2012#endif /* SLJIT_CONFIG_ARM_V6 */20132014/* Create imm by 1 inst. */2015tmp = get_imm(imm);2016if (tmp)2017return push_inst(compiler, MOV | RD(reg) | tmp);20182019tmp = get_imm(~imm);2020if (tmp)2021return push_inst(compiler, MVN | RD(reg) | tmp);20222023#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)2024/* Create imm by 2 inst. */2025imm1 = compute_imm(imm, &imm2);2026if (imm1 != 0) {2027FAIL_IF(push_inst(compiler, MOV | RD(reg) | imm1));2028return push_inst(compiler, ORR | RD(reg) | RN(reg) | imm2);2029}20302031imm1 = compute_imm(~imm, &imm2);2032if (imm1 != 0) {2033FAIL_IF(push_inst(compiler, MVN | RD(reg) | imm1));2034return push_inst(compiler, BIC | RD(reg) | RN(reg) | imm2);2035}20362037/* Load integer. */2038return push_inst_with_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, reg, TMP_PC, 0), imm);2039#else /* !SLJIT_CONFIG_ARM_V6 */2040FAIL_IF(push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff)));2041if (imm <= 0xffff)2042return SLJIT_SUCCESS;2043return push_inst(compiler, MOVT | RD(reg) | ((imm >> 12) & 0xf0000) | ((imm >> 16) & 0xfff));2044#endif /* SLJIT_CONFIG_ARM_V6 */2045}20462047static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg,2048sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg)2049{2050sljit_uw imm, offset_reg, tmp;2051sljit_sw mask = IS_TYPE1_TRANSFER(flags) ? 0xfff : 0xff;2052sljit_sw sign = IS_TYPE1_TRANSFER(flags) ? 0x1000 : 0x100;20532054SLJIT_ASSERT(arg & SLJIT_MEM);2055SLJIT_ASSERT((arg & REG_MASK) != tmp_reg || (arg == SLJIT_MEM1(tmp_reg) && argw >= -mask && argw <= mask));20562057if (SLJIT_UNLIKELY(!(arg & REG_MASK))) {2058tmp = (sljit_uw)(argw & (sign | mask));2059tmp = (sljit_uw)((argw + (tmp <= (sljit_uw)sign ? 0 : sign)) & ~mask);20602061FAIL_IF(load_immediate(compiler, tmp_reg, tmp));20622063argw -= (sljit_sw)tmp;2064tmp = 1;20652066if (argw < 0) {2067argw = -argw;2068tmp = 0;2069}20702071return push_inst(compiler, EMIT_DATA_TRANSFER(flags, tmp, reg, tmp_reg,2072(mask == 0xff) ? TYPE2_TRANSFER_IMM(argw) : argw));2073}20742075if (arg & OFFS_REG_MASK) {2076offset_reg = OFFS_REG(arg);2077arg &= REG_MASK;2078argw &= 0x3;20792080if (argw != 0 && (mask == 0xff)) {2081FAIL_IF(push_inst(compiler, ADD | RD(tmp_reg) | RN(arg) | RM(offset_reg) | ((sljit_ins)argw << 7)));2082return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, tmp_reg, TYPE2_TRANSFER_IMM(0)));2083}20842085/* Bit 25: RM is offset. */2086return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, arg,2087RM(offset_reg) | (mask == 0xff ? 0 : (1 << 25)) | ((sljit_ins)argw << 7)));2088}20892090arg &= REG_MASK;20912092if (argw > mask) {2093tmp = (sljit_uw)(argw & (sign | mask));2094tmp = (sljit_uw)((argw + (tmp <= (sljit_uw)sign ? 0 : sign)) & ~mask);2095imm = get_imm(tmp);20962097if (imm) {2098FAIL_IF(push_inst(compiler, ADD | RD(tmp_reg) | RN(arg) | imm));2099argw -= (sljit_sw)tmp;2100arg = tmp_reg;21012102SLJIT_ASSERT(argw >= -mask && argw <= mask);2103}2104} else if (argw < -mask) {2105tmp = (sljit_uw)(-argw & (sign | mask));2106tmp = (sljit_uw)((-argw + (tmp <= (sljit_uw)sign ? 0 : sign)) & ~mask);2107imm = get_imm(tmp);21082109if (imm) {2110FAIL_IF(push_inst(compiler, SUB | RD(tmp_reg) | RN(arg) | imm));2111argw += (sljit_sw)tmp;2112arg = tmp_reg;21132114SLJIT_ASSERT(argw >= -mask && argw <= mask);2115}2116}21172118if (argw <= mask && argw >= -mask) {2119if (argw >= 0) {2120if (mask == 0xff)2121argw = TYPE2_TRANSFER_IMM(argw);2122return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, arg, argw));2123}21242125argw = -argw;21262127if (mask == 0xff)2128argw = TYPE2_TRANSFER_IMM(argw);21292130return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 0, reg, arg, argw));2131}21322133FAIL_IF(load_immediate(compiler, tmp_reg, (sljit_uw)argw));2134return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, arg,2135RM(tmp_reg) | (mask == 0xff ? 0 : (1 << 25))));2136}21372138static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 inp_flags,2139sljit_s32 dst, sljit_sw dstw,2140sljit_s32 src1, sljit_sw src1w,2141sljit_s32 src2, sljit_sw src2w)2142{2143/* src1 is reg or TMP_REG12144src2 is reg, TMP_REG2, or imm2145result goes to TMP_REG2, so put result can use TMP_REG1. */21462147/* We prefers register and simple consts. */2148sljit_s32 dst_reg;2149sljit_s32 src1_reg = 0;2150sljit_s32 src2_reg = 0;2151sljit_s32 src2_tmp_reg = 0;2152sljit_s32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;2153sljit_s32 neg_op = 0;2154sljit_u32 imm2;21552156op = GET_OPCODE(op);21572158if (flags & SET_FLAGS)2159inp_flags &= ~ALLOW_DOUBLE_IMM;21602161if (dst == TMP_REG1)2162flags |= UNUSED_RETURN;21632164SLJIT_ASSERT(!(inp_flags & ALLOW_INV_IMM) || (inp_flags & ALLOW_IMM));21652166if (inp_flags & ALLOW_NEG_IMM) {2167switch (op) {2168case SLJIT_ADD:2169compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;2170neg_op = SLJIT_SUB;2171break;2172case SLJIT_ADDC:2173compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;2174neg_op = SLJIT_SUBC;2175break;2176case SLJIT_SUB:2177compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;2178neg_op = SLJIT_ADD;2179break;2180case SLJIT_SUBC:2181compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;2182neg_op = SLJIT_ADDC;2183break;2184}2185}21862187do {2188if (!(inp_flags & ALLOW_IMM))2189break;21902191if (src2 == SLJIT_IMM) {2192src2_reg = (sljit_s32)get_imm((sljit_uw)src2w);2193if (src2_reg)2194break;21952196if (inp_flags & ALLOW_INV_IMM) {2197src2_reg = (sljit_s32)get_imm(~(sljit_uw)src2w);2198if (src2_reg) {2199flags |= INV_IMM;2200break;2201}2202}22032204if (neg_op != 0) {2205src2_reg = (sljit_s32)get_imm((neg_op == SLJIT_ADD || neg_op == SLJIT_SUB) ? (sljit_uw)-src2w : ~(sljit_uw)src2w);2206if (src2_reg) {2207op = neg_op | GET_ALL_FLAGS(op);2208break;2209}2210}2211}22122213if (src1 == SLJIT_IMM) {2214src2_reg = (sljit_s32)get_imm((sljit_uw)src1w);2215if (src2_reg) {2216flags |= ARGS_SWAPPED;2217src1 = src2;2218src1w = src2w;2219break;2220}22212222if (inp_flags & ALLOW_INV_IMM) {2223src2_reg = (sljit_s32)get_imm(~(sljit_uw)src1w);2224if (src2_reg) {2225flags |= ARGS_SWAPPED | INV_IMM;2226src1 = src2;2227src1w = src2w;2228break;2229}2230}22312232if (neg_op >= SLJIT_SUB) {2233/* Note: additive operation (commutative). */2234SLJIT_ASSERT(op == SLJIT_ADD || op == SLJIT_ADDC);22352236src2_reg = (sljit_s32)get_imm((sljit_uw)-src1w);2237if (src2_reg) {2238src1 = src2;2239src1w = src2w;2240op = neg_op | GET_ALL_FLAGS(op);2241break;2242}2243}2244}2245} while(0);22462247/* Destination. */2248dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG2;22492250if (op <= SLJIT_MOV_P) {2251if (dst & SLJIT_MEM) {2252if (inp_flags & BYTE_SIZE)2253inp_flags &= ~SIGNED;22542255if (FAST_IS_REG(src2))2256return emit_op_mem(compiler, inp_flags, src2, dst, dstw, TMP_REG1);2257}22582259if (FAST_IS_REG(src2) && dst_reg != TMP_REG2)2260flags |= REGISTER_OP;22612262src2_tmp_reg = dst_reg;2263} else {2264if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16) {2265if (!(dst & SLJIT_MEM) && (!(src2 & SLJIT_MEM) || op == SLJIT_REV_S16))2266flags |= REGISTER_OP;2267}22682269src2_tmp_reg = FAST_IS_REG(src1) ? TMP_REG1 : TMP_REG2;2270}22712272if (src2_reg == 0 && (src2 & SLJIT_MEM)) {2273src2_reg = src2_tmp_reg;2274FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, src2_reg, src2, src2w, TMP_REG1));2275}22762277/* Source 1. */2278if (FAST_IS_REG(src1))2279src1_reg = src1;2280else if (src1 & SLJIT_MEM) {2281FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));2282src1_reg = TMP_REG1;2283} else if (!(inp_flags & ALLOW_DOUBLE_IMM) || src2_reg != 0 || op == SLJIT_SUB || op == SLJIT_SUBC) {2284FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));2285src1_reg = TMP_REG1;2286}22872288/* Source 2. */2289if (src2_reg == 0) {2290src2_reg = src2_tmp_reg;22912292if (FAST_IS_REG(src2))2293src2_reg = src2;2294else if (!(inp_flags & ALLOW_DOUBLE_IMM))2295FAIL_IF(load_immediate(compiler, src2_reg, (sljit_uw)src2w));2296else {2297SLJIT_ASSERT(!(flags & SET_FLAGS));22982299if (src1_reg == 0) {2300FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));2301src1_reg = TMP_REG1;2302}23032304src2_reg = (sljit_s32)compute_imm((sljit_uw)src2w, &imm2);23052306if (src2_reg == 0 && neg_op != 0) {2307src2_reg = (sljit_s32)compute_imm((sljit_uw)-src2w, &imm2);2308if (src2_reg != 0)2309op = neg_op;2310}23112312if (src2_reg == 0) {2313FAIL_IF(load_immediate(compiler, src2_tmp_reg, (sljit_uw)src2w));2314src2_reg = src2_tmp_reg;2315} else {2316FAIL_IF(emit_single_op(compiler, op, flags, (sljit_uw)dst_reg, (sljit_uw)src1_reg, (sljit_uw)src2_reg));2317src1_reg = dst_reg;2318src2_reg = (sljit_s32)imm2;23192320if (op == SLJIT_ADDC)2321op = SLJIT_ADD;2322else if (op == SLJIT_SUBC)2323op = SLJIT_SUB;2324}2325}2326}23272328if (src1_reg == 0) {2329SLJIT_ASSERT((inp_flags & ALLOW_DOUBLE_IMM) && !(flags & SET_FLAGS));23302331src1_reg = (sljit_s32)compute_imm((sljit_uw)src1w, &imm2);23322333if (src1_reg == 0 && neg_op != 0) {2334src1_reg = (sljit_s32)compute_imm((sljit_uw)-src1w, &imm2);2335if (src1_reg != 0)2336op = neg_op;2337}23382339if (src1_reg == 0) {2340FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));2341src1_reg = TMP_REG1;2342} else {2343FAIL_IF(emit_single_op(compiler, op, flags, (sljit_uw)dst_reg, (sljit_uw)src2_reg, (sljit_uw)src1_reg));2344src1_reg = dst_reg;2345src2_reg = (sljit_s32)imm2;23462347if (op == SLJIT_ADDC)2348op = SLJIT_ADD;2349}2350}23512352FAIL_IF(emit_single_op(compiler, op, flags, (sljit_uw)dst_reg, (sljit_uw)src1_reg, (sljit_uw)src2_reg));23532354if (!(dst & SLJIT_MEM))2355return SLJIT_SUCCESS;23562357return emit_op_mem(compiler, inp_flags, dst_reg, dst, dstw, TMP_REG1);2358}23592360#ifdef __cplusplus2361extern "C" {2362#endif23632364#if defined(__GNUC__)2365extern unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator);2366extern int __aeabi_idivmod(int numerator, int denominator);2367#else2368#error "Software divmod functions are needed"2369#endif23702371#ifdef __cplusplus2372}2373#endif23742375SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)2376{2377sljit_uw saved_reg_list[3];2378sljit_sw saved_reg_count;23792380CHECK_ERROR();2381CHECK(check_sljit_emit_op0(compiler, op));23822383op = GET_OPCODE(op);2384switch (op) {2385case SLJIT_BREAKPOINT:2386FAIL_IF(push_inst(compiler, BKPT));2387break;2388case SLJIT_NOP:2389FAIL_IF(push_inst(compiler, NOP));2390break;2391case SLJIT_LMUL_UW:2392case SLJIT_LMUL_SW:2393return push_inst(compiler, (op == SLJIT_LMUL_UW ? UMULL : SMULL)2394| RN(SLJIT_R1) | RD(SLJIT_R0) | RM8(SLJIT_R0) | RM(SLJIT_R1));2395case SLJIT_DIVMOD_UW:2396case SLJIT_DIVMOD_SW:2397case SLJIT_DIV_UW:2398case SLJIT_DIV_SW:2399SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);2400SLJIT_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 3);24012402saved_reg_count = 0;2403if (compiler->scratches >= 4)2404saved_reg_list[saved_reg_count++] = 3;2405if (compiler->scratches >= 3)2406saved_reg_list[saved_reg_count++] = 2;2407if (op >= SLJIT_DIV_UW)2408saved_reg_list[saved_reg_count++] = 1;24092410if (saved_reg_count > 0) {2411FAIL_IF(push_inst(compiler, STR | 0x2d0000 | (saved_reg_count >= 3 ? 16 : 8)2412| (saved_reg_list[0] << 12) /* str rX, [sp, #-8/-16]! */));2413if (saved_reg_count >= 2) {2414SLJIT_ASSERT(saved_reg_list[1] < 8);2415FAIL_IF(push_inst(compiler, STR | 0x8d0004 | (saved_reg_list[1] << 12) /* str rX, [sp, #4] */));2416}2417if (saved_reg_count >= 3) {2418SLJIT_ASSERT(saved_reg_list[2] < 8);2419FAIL_IF(push_inst(compiler, STR | 0x8d0008 | (saved_reg_list[2] << 12) /* str rX, [sp, #8] */));2420}2421}24222423#if defined(__GNUC__)2424FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM,2425((op | 0x2) == SLJIT_DIV_UW ? SLJIT_FUNC_ADDR(__aeabi_uidivmod) : SLJIT_FUNC_ADDR(__aeabi_idivmod))));2426#else2427#error "Software divmod functions are needed"2428#endif24292430if (saved_reg_count > 0) {2431if (saved_reg_count >= 3) {2432SLJIT_ASSERT(saved_reg_list[2] < 8);2433FAIL_IF(push_inst(compiler, LDR | 0x8d0008 | (saved_reg_list[2] << 12) /* ldr rX, [sp, #8] */));2434}2435if (saved_reg_count >= 2) {2436SLJIT_ASSERT(saved_reg_list[1] < 8);2437FAIL_IF(push_inst(compiler, LDR | 0x8d0004 | (saved_reg_list[1] << 12) /* ldr rX, [sp, #4] */));2438}2439return push_inst(compiler, (LDR ^ (1 << 24)) | 0x8d0000 | (sljit_ins)(saved_reg_count >= 3 ? 16 : 8)2440| (saved_reg_list[0] << 12) /* ldr rX, [sp], #8/16 */);2441}2442return SLJIT_SUCCESS;2443case SLJIT_MEMORY_BARRIER:2444#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)2445return push_inst(compiler, DMB_SY);2446#else /* !SLJIT_CONFIG_ARM_V7 */2447return SLJIT_ERR_UNSUPPORTED;2448#endif /* SLJIT_CONFIG_ARM_V7 */2449case SLJIT_ENDBR:2450case SLJIT_SKIP_FRAMES_BEFORE_RETURN:2451return SLJIT_SUCCESS;2452}24532454return SLJIT_SUCCESS;2455}24562457SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,2458sljit_s32 dst, sljit_sw dstw,2459sljit_s32 src, sljit_sw srcw)2460{2461CHECK_ERROR();2462CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));2463ADJUST_LOCAL_OFFSET(dst, dstw);2464ADJUST_LOCAL_OFFSET(src, srcw);24652466switch (GET_OPCODE(op)) {2467case SLJIT_MOV:2468case SLJIT_MOV_U32:2469case SLJIT_MOV_S32:2470case SLJIT_MOV32:2471case SLJIT_MOV_P:2472return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw);24732474case SLJIT_MOV_U8:2475return emit_op(compiler, SLJIT_MOV_U8, ALLOW_ANY_IMM | BYTE_SIZE, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u8)srcw : srcw);24762477case SLJIT_MOV_S8:2478return emit_op(compiler, SLJIT_MOV_S8, ALLOW_ANY_IMM | SIGNED | BYTE_SIZE, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s8)srcw : srcw);24792480case SLJIT_MOV_U16:2481return emit_op(compiler, SLJIT_MOV_U16, ALLOW_ANY_IMM | HALF_SIZE, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u16)srcw : srcw);24822483case SLJIT_MOV_S16:2484return emit_op(compiler, SLJIT_MOV_S16, ALLOW_ANY_IMM | SIGNED | HALF_SIZE, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s16)srcw : srcw);24852486case SLJIT_CLZ:2487case SLJIT_CTZ:2488case SLJIT_REV:2489case SLJIT_REV_U32:2490case SLJIT_REV_S32:2491return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src, srcw);24922493case SLJIT_REV_U16:2494case SLJIT_REV_S16:2495return emit_op(compiler, op, HALF_SIZE, dst, dstw, TMP_REG1, 0, src, srcw);2496}24972498return SLJIT_SUCCESS;2499}25002501SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,2502sljit_s32 dst, sljit_sw dstw,2503sljit_s32 src1, sljit_sw src1w,2504sljit_s32 src2, sljit_sw src2w)2505{2506sljit_s32 inp_flags;25072508CHECK_ERROR();2509CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w));2510ADJUST_LOCAL_OFFSET(dst, dstw);2511ADJUST_LOCAL_OFFSET(src1, src1w);2512ADJUST_LOCAL_OFFSET(src2, src2w);25132514switch (GET_OPCODE(op)) {2515case SLJIT_ADD:2516case SLJIT_ADDC:2517case SLJIT_SUB:2518case SLJIT_SUBC:2519return emit_op(compiler, op, ALLOW_IMM | ALLOW_NEG_IMM | ALLOW_DOUBLE_IMM, dst, dstw, src1, src1w, src2, src2w);25202521case SLJIT_OR:2522return emit_op(compiler, op, ALLOW_IMM | ALLOW_DOUBLE_IMM, dst, dstw, src1, src1w, src2, src2w);25232524case SLJIT_XOR:2525inp_flags = ALLOW_IMM | ALLOW_DOUBLE_IMM;2526if ((src1 == SLJIT_IMM && src1w == -1) || (src2 == SLJIT_IMM && src2w == -1)) {2527inp_flags |= ALLOW_INV_IMM;2528}2529return emit_op(compiler, op, inp_flags, dst, dstw, src1, src1w, src2, src2w);25302531case SLJIT_MUL:2532return emit_op(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w);25332534case SLJIT_AND:2535return emit_op(compiler, op, ALLOW_ANY_IMM, dst, dstw, src1, src1w, src2, src2w);25362537case SLJIT_SHL:2538case SLJIT_MSHL:2539case SLJIT_LSHR:2540case SLJIT_MLSHR:2541case SLJIT_ASHR:2542case SLJIT_MASHR:2543case SLJIT_ROTL:2544case SLJIT_ROTR:2545if (src2 == SLJIT_IMM) {2546compiler->shift_imm = src2w & 0x1f;2547return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src1, src1w);2548} else {2549compiler->shift_imm = 0x20;2550return emit_op(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w);2551}2552}25532554return SLJIT_SUCCESS;2555}25562557SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op,2558sljit_s32 src1, sljit_sw src1w,2559sljit_s32 src2, sljit_sw src2w)2560{2561CHECK_ERROR();2562CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));25632564SLJIT_SKIP_CHECKS(compiler);2565return sljit_emit_op2(compiler, op, TMP_REG1, 0, src1, src1w, src2, src2w);2566}25672568SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,2569sljit_s32 dst_reg,2570sljit_s32 src1, sljit_sw src1w,2571sljit_s32 src2, sljit_sw src2w)2572{2573CHECK_ERROR();2574CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w));2575ADJUST_LOCAL_OFFSET(src1, src1w);2576ADJUST_LOCAL_OFFSET(src2, src2w);25772578switch (GET_OPCODE(op)) {2579case SLJIT_MULADD:2580return emit_op(compiler, op, 0, dst_reg, 0, src1, src1w, src2, src2w);2581}25822583return SLJIT_SUCCESS;2584}25852586SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,2587sljit_s32 dst_reg,2588sljit_s32 src1_reg,2589sljit_s32 src2_reg,2590sljit_s32 src3, sljit_sw src3w)2591{2592sljit_s32 is_left;25932594CHECK_ERROR();2595CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));25962597op = GET_OPCODE(op);2598is_left = (op == SLJIT_SHL || op == SLJIT_MSHL);25992600if (src1_reg == src2_reg) {2601SLJIT_SKIP_CHECKS(compiler);2602return sljit_emit_op2(compiler, is_left ? SLJIT_ROTL : SLJIT_ROTR, dst_reg, 0, src1_reg, 0, src3, src3w);2603}26042605ADJUST_LOCAL_OFFSET(src3, src3w);26062607/* Shift type of ROR is 3. */2608if (src3 == SLJIT_IMM) {2609src3w &= 0x1f;26102611if (src3w == 0)2612return SLJIT_SUCCESS;26132614FAIL_IF(push_inst(compiler, MOV | RD(dst_reg) | RM(src1_reg) | ((sljit_ins)(is_left ? 0 : 1) << 5) | ((sljit_ins)src3w << 7)));2615src3w = (src3w ^ 0x1f) + 1;2616return push_inst(compiler, ORR | RD(dst_reg) | RN(dst_reg) | RM(src2_reg) | ((sljit_ins)(is_left ? 1 : 0) << 5) | ((sljit_ins)src3w << 7));2617}26182619if (src3 & SLJIT_MEM) {2620FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, src3, src3w, TMP_REG2));2621src3 = TMP_REG2;2622}26232624if (op == SLJIT_MSHL || op == SLJIT_MLSHR || dst_reg == src3) {2625FAIL_IF(push_inst(compiler, AND | SRC2_IMM | RD(TMP_REG2) | RN(src3) | 0x1f));2626src3 = TMP_REG2;2627}26282629FAIL_IF(push_inst(compiler, MOV | RD(dst_reg) | RM8(src3) | ((sljit_ins)(is_left ? 0 : 1) << 5) | 0x10 | RM(src1_reg)));2630FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | RM(src2_reg) | ((sljit_ins)(is_left ? 1 : 0) << 5) | (1 << 7)));2631FAIL_IF(push_inst(compiler, EOR | SRC2_IMM | RD(TMP_REG2) | RN(src3) | 0x1f));2632return push_inst(compiler, ORR | RD(dst_reg) | RN(dst_reg) | RM8(TMP_REG2) | ((sljit_ins)(is_left ? 1 : 0) << 5) | 0x10 | RM(TMP_REG1));2633}26342635SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2_shift(struct sljit_compiler *compiler, sljit_s32 op,2636sljit_s32 dst, sljit_sw dstw,2637sljit_s32 src1, sljit_sw src1w,2638sljit_s32 src2, sljit_sw src2w,2639sljit_sw shift_arg)2640{2641sljit_s32 dst_r, tmp_r;26422643CHECK_ERROR();2644CHECK(check_sljit_emit_op2_shift(compiler, op, dst, dstw, src1, src1w, src2, src2w, shift_arg));2645ADJUST_LOCAL_OFFSET(dst, dstw);2646ADJUST_LOCAL_OFFSET(src1, src1w);2647ADJUST_LOCAL_OFFSET(src2, src2w);26482649shift_arg &= 0x1f;26502651if (src2 == SLJIT_IMM) {2652src2w = src2w << shift_arg;2653shift_arg = 0;2654}26552656if (shift_arg == 0) {2657SLJIT_SKIP_CHECKS(compiler);2658return sljit_emit_op2(compiler, GET_OPCODE(op), dst, dstw, src1, src1w, src2, src2w);2659}26602661if (src1 == SLJIT_IMM) {2662FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));2663src1 = TMP_REG1;2664} else if (src1 & SLJIT_MEM) {2665FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));2666src1 = TMP_REG1;2667}26682669if (src2 & SLJIT_MEM) {2670tmp_r = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;2671FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, tmp_r, src2, src2w, tmp_r));2672src2 = tmp_r;2673}26742675dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;2676FAIL_IF(push_inst(compiler, ADD | RD(dst_r) | RN(src1) | RM(src2) | ((sljit_ins)shift_arg << 7)));26772678if (dst & SLJIT_MEM)2679return emit_op_mem(compiler, WORD_SIZE, dst_r, dst, dstw, TMP_REG1);2680return SLJIT_SUCCESS;2681}26822683SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,2684sljit_s32 src, sljit_sw srcw)2685{2686CHECK_ERROR();2687CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));2688ADJUST_LOCAL_OFFSET(src, srcw);26892690switch (op) {2691case SLJIT_FAST_RETURN:2692SLJIT_ASSERT(reg_map[TMP_REG2] == 14);26932694if (FAST_IS_REG(src)) {2695if (src != TMP_REG2)2696FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG2) | RM(src)));2697} else2698FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, src, srcw, TMP_REG1));26992700return push_inst(compiler, BX | RM(TMP_REG2));2701case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:2702return SLJIT_SUCCESS;2703case SLJIT_PREFETCH_L1:2704case SLJIT_PREFETCH_L2:2705case SLJIT_PREFETCH_L3:2706case SLJIT_PREFETCH_ONCE:2707SLJIT_ASSERT(src & SLJIT_MEM);2708return emit_op_mem(compiler, PRELOAD | LOAD_DATA, TMP_PC, src, srcw, TMP_REG1);2709}27102711return SLJIT_SUCCESS;2712}27132714SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,2715sljit_s32 dst, sljit_sw dstw)2716{2717sljit_s32 size, dst_r;27182719CHECK_ERROR();2720CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));2721ADJUST_LOCAL_OFFSET(dst, dstw);27222723switch (op) {2724case SLJIT_FAST_ENTER:2725SLJIT_ASSERT(reg_map[TMP_REG2] == 14);27262727if (FAST_IS_REG(dst)) {2728if (dst == TMP_REG2)2729return SLJIT_SUCCESS;2730return push_inst(compiler, MOV | RD(dst) | RM(TMP_REG2));2731}2732break;2733case SLJIT_GET_RETURN_ADDRESS:2734size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds - SLJIT_KEPT_SAVEDS_COUNT(compiler->options), 0);27352736if (compiler->fsaveds > 0 || compiler->fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {2737/* The size of pc is not added above. */2738if ((size & SSIZE_OF(sw)) == 0)2739size += SSIZE_OF(sw);27402741size += GET_SAVED_FLOAT_REGISTERS_SIZE(compiler->fscratches, compiler->fsaveds, f64);2742}27432744SLJIT_ASSERT(((compiler->local_size + size + SSIZE_OF(sw)) & 0x7) == 0);27452746dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;2747FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, dst_r, SLJIT_MEM1(SLJIT_SP), compiler->local_size + size, TMP_REG1));2748break;2749}27502751if (dst & SLJIT_MEM)2752return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1);27532754return SLJIT_SUCCESS;2755}27562757SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)2758{2759CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));27602761if (type == SLJIT_GP_REGISTER)2762return reg_map[reg];27632764if (type == SLJIT_FLOAT_REGISTER || type == SLJIT_SIMD_REG_64)2765return freg_map[reg];27662767if (type == SLJIT_SIMD_REG_128)2768return freg_map[reg] & ~0x1;27692770return -1;2771}27722773SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,2774void *instruction, sljit_u32 size)2775{2776SLJIT_UNUSED_ARG(size);2777CHECK_ERROR();2778CHECK(check_sljit_emit_op_custom(compiler, instruction, size));27792780return push_inst(compiler, *(sljit_ins*)instruction);2781}27822783/* --------------------------------------------------------------------- */2784/* Floating point operators */2785/* --------------------------------------------------------------------- */27862787#define FPU_LOAD (1 << 20)2788#define EMIT_FPU_DATA_TRANSFER(inst, add, base, freg, offs) \2789((inst) | (sljit_ins)((add) << 23) | RN(base) | VD(freg) | (sljit_ins)(offs))27902791static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)2792{2793sljit_uw imm;2794sljit_ins inst = VSTR_F32 | (flags & (SLJIT_32 | FPU_LOAD));27952796SLJIT_ASSERT(arg & SLJIT_MEM);2797arg &= ~SLJIT_MEM;27982799if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {2800FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (((sljit_ins)argw & 0x3) << 7)));2801arg = TMP_REG1;2802argw = 0;2803}28042805/* Fast loads and stores. */2806if (arg) {2807if (!(argw & ~0x3fc))2808return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, arg & REG_MASK, reg, argw >> 2));2809if (!(-argw & ~0x3fc))2810return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, arg & REG_MASK, reg, (-argw) >> 2));28112812imm = get_imm((sljit_uw)argw & ~(sljit_uw)0x3fc);2813if (imm) {2814FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | imm));2815return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG1, reg, (argw & 0x3fc) >> 2));2816}2817imm = get_imm((sljit_uw)-argw & ~(sljit_uw)0x3fc);2818if (imm) {2819argw = -argw;2820FAIL_IF(push_inst(compiler, SUB | RD(TMP_REG1) | RN(arg & REG_MASK) | imm));2821return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, TMP_REG1, reg, (argw & 0x3fc) >> 2));2822}2823}28242825if (arg) {2826FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)argw));2827FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(TMP_REG1)));2828}2829else2830FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)argw));28312832return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG1, reg, 0));2833}28342835static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,2836sljit_s32 dst, sljit_sw dstw,2837sljit_s32 src, sljit_sw srcw)2838{2839op ^= SLJIT_32;28402841if (src & SLJIT_MEM) {2842FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src, srcw));2843src = TMP_FREG1;2844}28452846FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_S32_F32, op & SLJIT_32, TMP_FREG1, src, 0)));28472848if (FAST_IS_REG(dst))2849return push_inst(compiler, VMOV | (1 << 20) | RD(dst) | VN(TMP_FREG1));28502851/* Store the integer value from a VFP register. */2852return emit_fop_mem(compiler, 0, TMP_FREG1, dst, dstw);2853}28542855static sljit_s32 sljit_emit_fop1_conv_f64_from_w(struct sljit_compiler *compiler, sljit_ins ins,2856sljit_s32 dst, sljit_sw dstw,2857sljit_s32 src, sljit_sw srcw)2858{2859sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;28602861if (FAST_IS_REG(src))2862FAIL_IF(push_inst(compiler, VMOV | RD(src) | VN(TMP_FREG1)));2863else if (src & SLJIT_MEM) {2864/* Load the integer value into a VFP register. */2865FAIL_IF(emit_fop_mem(compiler, FPU_LOAD, TMP_FREG1, src, srcw));2866}2867else {2868FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcw));2869FAIL_IF(push_inst(compiler, VMOV | RD(TMP_REG1) | VN(TMP_FREG1)));2870}28712872FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(ins, ins & SLJIT_32, dst_r, TMP_FREG1, 0)));28732874if (dst & SLJIT_MEM)2875return emit_fop_mem(compiler, (ins & SLJIT_32), TMP_FREG1, dst, dstw);2876return SLJIT_SUCCESS;2877}28782879static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,2880sljit_s32 dst, sljit_sw dstw,2881sljit_s32 src, sljit_sw srcw)2882{2883return sljit_emit_fop1_conv_f64_from_w(compiler, VCVT_F32_S32 | (~op & SLJIT_32), dst, dstw, src, srcw);2884}28852886static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,2887sljit_s32 dst, sljit_sw dstw,2888sljit_s32 src, sljit_sw srcw)2889{2890return sljit_emit_fop1_conv_f64_from_w(compiler, VCVT_F32_U32 | (~op & SLJIT_32), dst, dstw, src, srcw);2891}28922893static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,2894sljit_s32 src1, sljit_sw src1w,2895sljit_s32 src2, sljit_sw src2w)2896{2897op ^= SLJIT_32;28982899if (src1 & SLJIT_MEM) {2900FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w));2901src1 = TMP_FREG1;2902}29032904if (src2 & SLJIT_MEM) {2905FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG2, src2, src2w));2906src2 = TMP_FREG2;2907}29082909FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCMP_F32, op & SLJIT_32, src1, src2, 0)));2910FAIL_IF(push_inst(compiler, VMRS));29112912if (GET_FLAG_TYPE(op) != SLJIT_UNORDERED_OR_EQUAL)2913return SLJIT_SUCCESS;29142915return push_inst(compiler, (CMP - CONDITIONAL) | (0x60000000 /* VS */) | SET_FLAGS | RN(TMP_REG1) | RM(TMP_REG1));2916}29172918SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,2919sljit_s32 dst, sljit_sw dstw,2920sljit_s32 src, sljit_sw srcw)2921{2922sljit_s32 dst_r;29232924CHECK_ERROR();29252926SLJIT_COMPILE_ASSERT((SLJIT_32 == 0x100), float_transfer_bit_error);2927SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);29282929dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;29302931if (GET_OPCODE(op) != SLJIT_CONV_F64_FROM_F32)2932op ^= SLJIT_32;29332934if (src & SLJIT_MEM) {2935FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, dst_r, src, srcw));2936src = dst_r;2937}29382939switch (GET_OPCODE(op)) {2940case SLJIT_MOV_F64:2941if (src != dst_r) {2942if (!(dst & SLJIT_MEM))2943FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, op & SLJIT_32, dst_r, src, 0)));2944else2945dst_r = src;2946}2947break;2948case SLJIT_NEG_F64:2949FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VNEG_F32, op & SLJIT_32, dst_r, src, 0)));2950break;2951case SLJIT_ABS_F64:2952FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VABS_F32, op & SLJIT_32, dst_r, src, 0)));2953break;2954case SLJIT_CONV_F64_FROM_F32:2955FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_F64_F32, op & SLJIT_32, dst_r, src, 0)));2956op ^= SLJIT_32;2957break;2958}29592960if (dst & SLJIT_MEM)2961return emit_fop_mem(compiler, (op & SLJIT_32), dst_r, dst, dstw);2962return SLJIT_SUCCESS;2963}29642965SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,2966sljit_s32 dst, sljit_sw dstw,2967sljit_s32 src1, sljit_sw src1w,2968sljit_s32 src2, sljit_sw src2w)2969{2970sljit_s32 dst_r;29712972CHECK_ERROR();2973CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));2974ADJUST_LOCAL_OFFSET(dst, dstw);2975ADJUST_LOCAL_OFFSET(src1, src1w);2976ADJUST_LOCAL_OFFSET(src2, src2w);29772978op ^= SLJIT_32;29792980dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;29812982if (src2 & SLJIT_MEM) {2983FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG2, src2, src2w));2984src2 = TMP_FREG2;2985}29862987if (src1 & SLJIT_MEM) {2988FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w));2989src1 = TMP_FREG1;2990}29912992switch (GET_OPCODE(op)) {2993case SLJIT_ADD_F64:2994FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VADD_F32, op & SLJIT_32, dst_r, src2, src1)));2995break;2996case SLJIT_SUB_F64:2997FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VSUB_F32, op & SLJIT_32, dst_r, src2, src1)));2998break;2999case SLJIT_MUL_F64:3000FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMUL_F32, op & SLJIT_32, dst_r, src2, src1)));3001break;3002case SLJIT_DIV_F64:3003FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VDIV_F32, op & SLJIT_32, dst_r, src2, src1)));3004break;3005case SLJIT_COPYSIGN_F64:3006FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(src2) | RD(TMP_REG1) | ((op & SLJIT_32) ? (1 << 7) : 0)));3007FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VABS_F32, op & SLJIT_32, dst_r, src1, 0)));3008FAIL_IF(push_inst(compiler, CMP | SET_FLAGS | RN(TMP_REG1) | SRC2_IMM | 0));3009return push_inst(compiler, EMIT_FPU_OPERATION((VNEG_F32 & ~COND_MASK) | 0xb0000000, op & SLJIT_32, dst_r, dst_r, 0));3010}30113012if (dst_r != dst)3013FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32), TMP_FREG1, dst, dstw));30143015return SLJIT_SUCCESS;3016}30173018#undef EMIT_FPU_DATA_TRANSFER30193020SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,3021sljit_s32 freg, sljit_f32 value)3022{3023#if defined(__ARM_NEON) && __ARM_NEON3024sljit_u32 exp;3025sljit_ins ins;3026#endif /* NEON */3027union {3028sljit_u32 imm;3029sljit_f32 value;3030} u;30313032CHECK_ERROR();3033CHECK(check_sljit_emit_fset32(compiler, freg, value));30343035u.value = value;30363037#if defined(__ARM_NEON) && __ARM_NEON3038if ((u.imm << (32 - 19)) == 0) {3039exp = (u.imm >> (23 + 2)) & 0x3f;30403041if (exp == 0x20 || exp == 0x1f) {3042ins = ((u.imm >> 24) & 0x80) | ((u.imm >> 19) & 0x7f);3043return push_inst(compiler, (VMOV_F32 ^ (1 << 6)) | ((ins & 0xf0) << 12) | VD(freg) | (ins & 0xf));3044}3045}3046#endif /* NEON */30473048FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm));3049return push_inst(compiler, VMOV | VN(freg) | RD(TMP_REG1));3050}30513052SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,3053sljit_s32 freg, sljit_f64 value)3054{3055#if defined(__ARM_NEON) && __ARM_NEON3056sljit_u32 exp;3057sljit_ins ins;3058#endif /* NEON */3059union {3060sljit_u32 imm[2];3061sljit_f64 value;3062} u;30633064CHECK_ERROR();3065CHECK(check_sljit_emit_fset64(compiler, freg, value));30663067u.value = value;30683069#if defined(__ARM_NEON) && __ARM_NEON3070if (u.imm[0] == 0 && (u.imm[1] << (64 - 48)) == 0) {3071exp = (u.imm[1] >> ((52 - 32) + 2)) & 0x1ff;30723073if (exp == 0x100 || exp == 0xff) {3074ins = ((u.imm[1] >> (56 - 32)) & 0x80) | ((u.imm[1] >> (48 - 32)) & 0x7f);3075return push_inst(compiler, (VMOV_F32 ^ (1 << 6)) | (1 << 8) | ((ins & 0xf0) << 12) | VD(freg) | (ins & 0xf));3076}3077}3078#endif /* NEON */30793080FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm[0]));3081if (u.imm[0] == u.imm[1])3082return push_inst(compiler, VMOV2 | RN(TMP_REG1) | RD(TMP_REG1) | VM(freg));30833084FAIL_IF(load_immediate(compiler, TMP_REG2, u.imm[1]));3085return push_inst(compiler, VMOV2 | RN(TMP_REG2) | RD(TMP_REG1) | VM(freg));3086}30873088SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,3089sljit_s32 freg, sljit_s32 reg)3090{3091sljit_s32 reg2;3092sljit_ins inst;30933094CHECK_ERROR();3095CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));30963097if (reg & REG_PAIR_MASK) {3098reg2 = REG_PAIR_SECOND(reg);3099reg = REG_PAIR_FIRST(reg);31003101inst = VMOV2 | RN(reg) | RD(reg2) | VM(freg);3102} else {3103inst = VMOV | VN(freg) | RD(reg);31043105if (!(op & SLJIT_32))3106inst |= 1 << 7;3107}31083109if (GET_OPCODE(op) == SLJIT_COPY_FROM_F64)3110inst |= 1 << 20;31113112return push_inst(compiler, inst);3113}31143115/* --------------------------------------------------------------------- */3116/* Conditional instructions */3117/* --------------------------------------------------------------------- */31183119static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)3120{3121switch (type) {3122case SLJIT_EQUAL:3123case SLJIT_ATOMIC_STORED:3124case SLJIT_F_EQUAL:3125case SLJIT_ORDERED_EQUAL:3126case SLJIT_UNORDERED_OR_EQUAL:3127return 0x00000000;31283129case SLJIT_NOT_EQUAL:3130case SLJIT_ATOMIC_NOT_STORED:3131case SLJIT_F_NOT_EQUAL:3132case SLJIT_UNORDERED_OR_NOT_EQUAL:3133case SLJIT_ORDERED_NOT_EQUAL:3134return 0x10000000;31353136case SLJIT_CARRY:3137if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD)3138return 0x20000000;3139SLJIT_FALLTHROUGH31403141case SLJIT_LESS:3142return 0x30000000;31433144case SLJIT_NOT_CARRY:3145if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD)3146return 0x30000000;3147SLJIT_FALLTHROUGH31483149case SLJIT_GREATER_EQUAL:3150return 0x20000000;31513152case SLJIT_GREATER:3153case SLJIT_UNORDERED_OR_GREATER:3154return 0x80000000;31553156case SLJIT_LESS_EQUAL:3157case SLJIT_F_LESS_EQUAL:3158case SLJIT_ORDERED_LESS_EQUAL:3159return 0x90000000;31603161case SLJIT_SIG_LESS:3162case SLJIT_UNORDERED_OR_LESS:3163return 0xb0000000;31643165case SLJIT_SIG_GREATER_EQUAL:3166case SLJIT_F_GREATER_EQUAL:3167case SLJIT_ORDERED_GREATER_EQUAL:3168return 0xa0000000;31693170case SLJIT_SIG_GREATER:3171case SLJIT_F_GREATER:3172case SLJIT_ORDERED_GREATER:3173return 0xc0000000;31743175case SLJIT_SIG_LESS_EQUAL:3176case SLJIT_UNORDERED_OR_LESS_EQUAL:3177return 0xd0000000;31783179case SLJIT_OVERFLOW:3180if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)))3181return 0x10000000;3182SLJIT_FALLTHROUGH31833184case SLJIT_UNORDERED:3185return 0x60000000;31863187case SLJIT_NOT_OVERFLOW:3188if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)))3189return 0x00000000;3190SLJIT_FALLTHROUGH31913192case SLJIT_ORDERED:3193return 0x70000000;31943195case SLJIT_F_LESS:3196case SLJIT_ORDERED_LESS:3197return 0x40000000;31983199case SLJIT_UNORDERED_OR_GREATER_EQUAL:3200return 0x50000000;32013202default:3203SLJIT_ASSERT(type >= SLJIT_JUMP && type <= SLJIT_CALL_REG_ARG);3204return 0xe0000000;3205}3206}32073208SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)3209{3210struct sljit_label *label;32113212CHECK_ERROR_PTR();3213CHECK_PTR(check_sljit_emit_label(compiler));32143215if (compiler->last_label && compiler->last_label->size == compiler->size)3216return compiler->last_label;32173218label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));3219PTR_FAIL_IF(!label);3220set_label(label, compiler);3221return label;3222}32233224SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_aligned_label(struct sljit_compiler *compiler,3225sljit_s32 alignment, struct sljit_read_only_buffer *buffers)3226{3227sljit_uw mask, i;3228struct sljit_label *label;3229struct sljit_label *next_label;3230struct sljit_extended_label *ext_label;32313232CHECK_ERROR_PTR();3233CHECK_PTR(check_sljit_emit_aligned_label(compiler, alignment, buffers));32343235sljit_reset_read_only_buffers(buffers);32363237#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)3238if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY))3239PTR_FAIL_IF(push_cpool(compiler));3240#endif /* SLJIT_CONFIG_ARM_V6 */32413242if (alignment <= SLJIT_LABEL_ALIGN_4) {3243SLJIT_SKIP_CHECKS(compiler);3244label = sljit_emit_label(compiler);3245PTR_FAIL_IF(!label);3246} else {3247/* The used space is filled with NOPs. */3248mask = ((sljit_uw)1 << alignment) - sizeof(sljit_ins);32493250for (i = (mask >> 2); i != 0; i--)3251PTR_FAIL_IF(push_inst(compiler, NOP));32523253ext_label = (struct sljit_extended_label*)ensure_abuf(compiler, sizeof(struct sljit_extended_label));3254PTR_FAIL_IF(!ext_label);3255set_extended_label(ext_label, compiler, SLJIT_LABEL_ALIGNED, mask);3256label = &ext_label->label;3257}32583259if (buffers == NULL)3260return label;32613262next_label = label;32633264while (1) {3265buffers->u.label = next_label;32663267for (i = (buffers->size + 3) >> 2; i > 0; i--)3268PTR_FAIL_IF(push_inst(compiler, NOP));32693270buffers = buffers->next;32713272if (buffers == NULL)3273break;32743275SLJIT_SKIP_CHECKS(compiler);3276next_label = sljit_emit_label(compiler);3277PTR_FAIL_IF(!next_label);3278}32793280return label;3281}32823283SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)3284{3285struct sljit_jump *jump;32863287CHECK_ERROR_PTR();3288CHECK_PTR(check_sljit_emit_jump(compiler, type));32893290jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));3291PTR_FAIL_IF(!jump);3292set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);3293type &= 0xff;32943295SLJIT_ASSERT(reg_map[TMP_REG1] != 14);32963297#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)3298if (type >= SLJIT_FAST_CALL)3299PTR_FAIL_IF(prepare_blx(compiler));33003301PTR_FAIL_IF(push_inst_with_unique_literal(compiler, ((EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1,3302type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0)) & ~COND_MASK) | get_cc(compiler, type), 0));3303jump->addr = compiler->size - 1;33043305if (jump->flags & SLJIT_REWRITABLE_JUMP)3306compiler->patches++;33073308if (type >= SLJIT_FAST_CALL) {3309jump->flags |= IS_BL;3310jump->addr = compiler->size;3311PTR_FAIL_IF(emit_blx(compiler));3312}3313#else /* !SLJIT_CONFIG_ARM_V6 */3314jump->addr = compiler->size;3315if (type >= SLJIT_FAST_CALL)3316jump->flags |= IS_BL;3317PTR_FAIL_IF(push_inst(compiler, (((type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)) & ~COND_MASK) | get_cc(compiler, type)));3318compiler->size += JUMP_MAX_SIZE - 1;3319#endif /* SLJIT_CONFIG_ARM_V6 */3320return jump;3321}33223323#ifdef __SOFTFP__33243325static sljit_s32 softfloat_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src, sljit_u32 *extra_space)3326{3327sljit_u32 is_tail_call = *extra_space & SLJIT_CALL_RETURN;3328sljit_u32 offset = 0;3329sljit_u32 word_arg_offset = 0;3330sljit_u32 src_offset = 4 * sizeof(sljit_sw);3331sljit_u32 float_arg_count = 0;3332sljit_s32 types = 0;3333sljit_u8 offsets[4];3334sljit_u8 *offset_ptr = offsets;33353336if (src && FAST_IS_REG(*src))3337src_offset = (sljit_u32)reg_map[*src] * sizeof(sljit_sw);33383339arg_types >>= SLJIT_ARG_SHIFT;33403341while (arg_types) {3342types = (types << SLJIT_ARG_SHIFT) | (arg_types & SLJIT_ARG_MASK);33433344switch (arg_types & SLJIT_ARG_MASK) {3345case SLJIT_ARG_TYPE_F64:3346if (offset & 0x7)3347offset += sizeof(sljit_sw);3348*offset_ptr++ = (sljit_u8)offset;3349offset += sizeof(sljit_f64);3350float_arg_count++;3351break;3352case SLJIT_ARG_TYPE_F32:3353*offset_ptr++ = (sljit_u8)offset;3354offset += sizeof(sljit_f32);3355float_arg_count++;3356break;3357default:3358*offset_ptr++ = (sljit_u8)offset;3359offset += sizeof(sljit_sw);3360word_arg_offset += sizeof(sljit_sw);3361break;3362}33633364arg_types >>= SLJIT_ARG_SHIFT;3365}33663367if (offset > 4 * sizeof(sljit_sw) && (!is_tail_call || offset > compiler->args_size)) {3368/* Keep lr register on the stack. */3369if (is_tail_call)3370offset += sizeof(sljit_sw);33713372offset = ((offset - 4 * sizeof(sljit_sw)) + 0x7) & ~(sljit_u32)0x7;33733374*extra_space = offset;33753376if (is_tail_call)3377FAIL_IF(emit_stack_frame_release(compiler, (sljit_s32)offset));3378else3379FAIL_IF(push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | SRC2_IMM | offset));3380} else {3381if (is_tail_call)3382FAIL_IF(emit_stack_frame_release(compiler, -1));3383*extra_space = 0;3384}33853386/* Process arguments in reversed direction. */3387while (types) {3388switch (types & SLJIT_ARG_MASK) {3389case SLJIT_ARG_TYPE_F64:3390float_arg_count--;3391offset = *(--offset_ptr);33923393SLJIT_ASSERT((offset & 0x7) == 0);33943395if (offset < 4 * sizeof(sljit_sw)) {3396if (src_offset == offset || src_offset == offset + sizeof(sljit_sw)) {3397FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | (src_offset >> 2)));3398*src = TMP_REG1;3399}3400FAIL_IF(push_inst(compiler, VMOV2 | 0x100000 | (offset << 10) | ((offset + sizeof(sljit_sw)) << 14) | float_arg_count));3401} else3402FAIL_IF(push_inst(compiler, VSTR_F32 | 0x800100 | RN(SLJIT_SP)3403| (float_arg_count << 12) | ((offset - 4 * sizeof(sljit_sw)) >> 2)));3404break;3405case SLJIT_ARG_TYPE_F32:3406float_arg_count--;3407offset = *(--offset_ptr);34083409if (offset < 4 * sizeof(sljit_sw)) {3410if (src_offset == offset) {3411FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | (src_offset >> 2)));3412*src = TMP_REG1;3413}3414FAIL_IF(push_inst(compiler, VMOV | 0x100000 | (float_arg_count << 16) | (offset << 10)));3415} else3416FAIL_IF(push_inst(compiler, VSTR_F32 | 0x800000 | RN(SLJIT_SP)3417| (float_arg_count << 12) | ((offset - 4 * sizeof(sljit_sw)) >> 2)));3418break;3419default:3420word_arg_offset -= sizeof(sljit_sw);3421offset = *(--offset_ptr);34223423SLJIT_ASSERT(offset >= word_arg_offset);34243425if (offset != word_arg_offset) {3426if (offset < 4 * sizeof(sljit_sw)) {3427if (src_offset == offset) {3428FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | (src_offset >> 2)));3429*src = TMP_REG1;3430}3431else if (src_offset == word_arg_offset) {3432*src = (sljit_s32)(SLJIT_R0 + (offset >> 2));3433src_offset = offset;3434}3435FAIL_IF(push_inst(compiler, MOV | (offset << 10) | (word_arg_offset >> 2)));3436} else3437FAIL_IF(push_inst(compiler, STR | 0x800000 | RN(SLJIT_SP) | (word_arg_offset << 10) | (offset - 4 * sizeof(sljit_sw))));3438}3439break;3440}34413442types >>= SLJIT_ARG_SHIFT;3443}34443445return SLJIT_SUCCESS;3446}34473448static sljit_s32 softfloat_post_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types)3449{3450if ((arg_types & SLJIT_ARG_MASK) == SLJIT_ARG_TYPE_F64)3451FAIL_IF(push_inst(compiler, VMOV2 | (1 << 16) | (0 << 12) | 0));3452if ((arg_types & SLJIT_ARG_MASK) == SLJIT_ARG_TYPE_F32)3453FAIL_IF(push_inst(compiler, VMOV | (0 << 16) | (0 << 12)));34543455return SLJIT_SUCCESS;3456}34573458#else /* !__SOFTFP__ */34593460static sljit_s32 hardfloat_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types)3461{3462sljit_u32 offset = SLJIT_FR0;3463sljit_u32 new_offset = SLJIT_FR0;3464sljit_u32 f32_offset = 0;34653466/* Remove return value. */3467arg_types >>= SLJIT_ARG_SHIFT;34683469while (arg_types) {3470switch (arg_types & SLJIT_ARG_MASK) {3471case SLJIT_ARG_TYPE_F64:3472if (offset != new_offset)3473FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32,3474SLJIT_32, new_offset, offset, 0)));34753476new_offset++;3477offset++;3478break;3479case SLJIT_ARG_TYPE_F32:3480if (f32_offset != 0) {3481FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32,34820x400000, f32_offset, offset, 0)));3483f32_offset = 0;3484} else {3485if (offset != new_offset)3486FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32,34870, new_offset, offset, 0)));3488f32_offset = new_offset;3489new_offset++;3490}3491offset++;3492break;3493}3494arg_types >>= SLJIT_ARG_SHIFT;3495}34963497return SLJIT_SUCCESS;3498}34993500#endif /* __SOFTFP__ */35013502SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,3503sljit_s32 arg_types)3504{3505#ifdef __SOFTFP__3506struct sljit_jump *jump;3507sljit_u32 extra_space = (sljit_u32)type;3508#endif35093510CHECK_ERROR_PTR();3511CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));35123513#ifdef __SOFTFP__3514if ((type & 0xff) != SLJIT_CALL_REG_ARG) {3515PTR_FAIL_IF(softfloat_call_with_args(compiler, arg_types, NULL, &extra_space));3516SLJIT_ASSERT((extra_space & 0x7) == 0);35173518if ((type & SLJIT_CALL_RETURN) && extra_space == 0)3519type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP);35203521SLJIT_SKIP_CHECKS(compiler);3522jump = sljit_emit_jump(compiler, type);3523PTR_FAIL_IF(jump == NULL);35243525if (extra_space > 0) {3526if (type & SLJIT_CALL_RETURN)3527PTR_FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1,3528TMP_REG2, SLJIT_SP, extra_space - sizeof(sljit_sw))));35293530PTR_FAIL_IF(push_inst(compiler, ADD | RD(SLJIT_SP) | RN(SLJIT_SP) | SRC2_IMM | extra_space));35313532if (type & SLJIT_CALL_RETURN) {3533PTR_FAIL_IF(push_inst(compiler, BX | RM(TMP_REG2)));3534return jump;3535}3536}35373538SLJIT_ASSERT(!(type & SLJIT_CALL_RETURN));3539PTR_FAIL_IF(softfloat_post_call_with_args(compiler, arg_types));3540return jump;3541}3542#endif /* __SOFTFP__ */35433544if (type & SLJIT_CALL_RETURN) {3545PTR_FAIL_IF(emit_stack_frame_release(compiler, -1));3546type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP);3547}35483549#ifndef __SOFTFP__3550if ((type & 0xff) != SLJIT_CALL_REG_ARG)3551PTR_FAIL_IF(hardfloat_call_with_args(compiler, arg_types));3552#endif /* !__SOFTFP__ */35533554SLJIT_SKIP_CHECKS(compiler);3555return sljit_emit_jump(compiler, type);3556}35573558SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)3559{3560struct sljit_jump *jump;35613562CHECK_ERROR();3563CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));3564ADJUST_LOCAL_OFFSET(src, srcw);35653566SLJIT_ASSERT(reg_map[TMP_REG1] != 14);35673568if (src != SLJIT_IMM) {3569if (FAST_IS_REG(src)) {3570SLJIT_ASSERT(reg_map[src] != 14);3571return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(src));3572}35733574SLJIT_ASSERT(src & SLJIT_MEM);3575FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));3576return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1));3577}35783579/* These jumps are converted to jump/call instructions when possible. */3580jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));3581FAIL_IF(!jump);3582set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0));3583jump->u.target = (sljit_uw)srcw;35843585#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)3586if (type >= SLJIT_FAST_CALL)3587FAIL_IF(prepare_blx(compiler));3588jump->addr = compiler->size;3589FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0), 0));3590if (type >= SLJIT_FAST_CALL) {3591jump->addr = compiler->size;3592FAIL_IF(emit_blx(compiler));3593}3594#else /* !SLJIT_CONFIG_ARM_V6 */3595jump->addr = compiler->size;3596FAIL_IF(push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)));3597compiler->size += JUMP_MAX_SIZE - 1;3598#endif /* SLJIT_CONFIG_ARM_V6 */3599return SLJIT_SUCCESS;3600}36013602SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,3603sljit_s32 arg_types,3604sljit_s32 src, sljit_sw srcw)3605{3606#ifdef __SOFTFP__3607sljit_u32 extra_space = (sljit_u32)type;3608#endif36093610CHECK_ERROR();3611CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));36123613if (src & SLJIT_MEM) {3614FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));3615src = TMP_REG1;3616}36173618if ((type & SLJIT_CALL_RETURN) && (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options)))) {3619FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | RM(src)));3620src = TMP_REG1;3621}36223623#ifdef __SOFTFP__3624if ((type & 0xff) != SLJIT_CALL_REG_ARG) {3625FAIL_IF(softfloat_call_with_args(compiler, arg_types, &src, &extra_space));3626SLJIT_ASSERT((extra_space & 0x7) == 0);36273628if ((type & SLJIT_CALL_RETURN) && extra_space == 0)3629type = SLJIT_JUMP;36303631SLJIT_SKIP_CHECKS(compiler);3632FAIL_IF(sljit_emit_ijump(compiler, type, src, srcw));36333634if (extra_space > 0) {3635if (type & SLJIT_CALL_RETURN)3636FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1,3637TMP_REG2, SLJIT_SP, extra_space - sizeof(sljit_sw))));36383639FAIL_IF(push_inst(compiler, ADD | RD(SLJIT_SP) | RN(SLJIT_SP) | SRC2_IMM | extra_space));36403641if (type & SLJIT_CALL_RETURN)3642return push_inst(compiler, BX | RM(TMP_REG2));3643}36443645SLJIT_ASSERT(!(type & SLJIT_CALL_RETURN));3646return softfloat_post_call_with_args(compiler, arg_types);3647}3648#endif /* __SOFTFP__ */36493650if (type & SLJIT_CALL_RETURN) {3651FAIL_IF(emit_stack_frame_release(compiler, -1));3652type = SLJIT_JUMP;3653}36543655#ifndef __SOFTFP__3656if ((type & 0xff) != SLJIT_CALL_REG_ARG)3657FAIL_IF(hardfloat_call_with_args(compiler, arg_types));3658#endif /* !__SOFTFP__ */36593660SLJIT_SKIP_CHECKS(compiler);3661return sljit_emit_ijump(compiler, type, src, srcw);3662}36633664#ifdef __SOFTFP__36653666static SLJIT_INLINE sljit_s32 emit_fmov_before_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)3667{3668if (compiler->options & SLJIT_ENTER_REG_ARG) {3669if (src == SLJIT_FR0)3670return SLJIT_SUCCESS;36713672SLJIT_SKIP_CHECKS(compiler);3673return sljit_emit_fop1(compiler, op, SLJIT_RETURN_FREG, 0, src, srcw);3674}36753676if (FAST_IS_REG(src)) {3677if (op & SLJIT_32)3678return push_inst(compiler, VMOV | (1 << 20) | RD(SLJIT_R0) | VN(src));3679return push_inst(compiler, VMOV2 | (1 << 20) | RD(SLJIT_R0) | RN(SLJIT_R1) | VM(src));3680}36813682SLJIT_SKIP_CHECKS(compiler);36833684if (op & SLJIT_32)3685return sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, src, srcw);3686return sljit_emit_mem(compiler, SLJIT_MOV, SLJIT_REG_PAIR(SLJIT_R0, SLJIT_R1), src, srcw);3687}36883689#endif /* __SOFTFP__ */36903691SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,3692sljit_s32 dst, sljit_sw dstw,3693sljit_s32 type)3694{3695sljit_s32 dst_reg, flags = GET_ALL_FLAGS(op);3696sljit_ins cc, ins;36973698CHECK_ERROR();3699CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));3700ADJUST_LOCAL_OFFSET(dst, dstw);37013702op = GET_OPCODE(op);3703cc = get_cc(compiler, type);3704dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1;37053706if (op < SLJIT_ADD) {3707FAIL_IF(push_inst(compiler, MOV | RD(dst_reg) | SRC2_IMM | 0));3708FAIL_IF(push_inst(compiler, ((MOV | RD(dst_reg) | SRC2_IMM | 1) & ~COND_MASK) | cc));3709if (dst & SLJIT_MEM)3710return emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2);3711return SLJIT_SUCCESS;3712}37133714ins = (op == SLJIT_AND ? AND : (op == SLJIT_OR ? ORR : EOR));37153716if (dst & SLJIT_MEM)3717FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, dst, dstw, TMP_REG2));37183719FAIL_IF(push_inst(compiler, ((ins | RD(dst_reg) | RN(dst_reg) | SRC2_IMM | 1) & ~COND_MASK) | cc));37203721if (op == SLJIT_AND)3722FAIL_IF(push_inst(compiler, ((ins | RD(dst_reg) | RN(dst_reg) | SRC2_IMM | 0) & ~COND_MASK) | (cc ^ 0x10000000)));37233724if (dst & SLJIT_MEM)3725FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2));37263727if (flags & SLJIT_SET_Z)3728return push_inst(compiler, MOV | SET_FLAGS | RD(TMP_REG2) | RM(dst_reg));3729return SLJIT_SUCCESS;3730}37313732SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,3733sljit_s32 dst_reg,3734sljit_s32 src1, sljit_sw src1w,3735sljit_s32 src2_reg)3736{3737sljit_ins cc, tmp, tmp2;37383739CHECK_ERROR();3740CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));37413742ADJUST_LOCAL_OFFSET(src1, src1w);37433744if (src2_reg != dst_reg && src1 == dst_reg) {3745src1 = src2_reg;3746src1w = 0;3747src2_reg = dst_reg;3748if (!(type & SLJIT_COMPARE_SELECT))3749type ^= 0x1;3750}37513752if (src1 & SLJIT_MEM) {3753FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, (src2_reg != dst_reg) ? dst_reg : TMP_REG1, src1, src1w, TMP_REG1));37543755if (src2_reg != dst_reg) {3756src1 = src2_reg;3757src1w = 0;3758if (!(type & SLJIT_COMPARE_SELECT))3759type ^= 0x1;3760} else {3761src1 = TMP_REG1;3762src1w = 0;3763}3764} else if (dst_reg != src2_reg)3765FAIL_IF(push_inst(compiler, MOV | RD(dst_reg) | RM(src2_reg)));37663767if (type & SLJIT_COMPARE_SELECT)3768type ^= 0x1;37693770cc = get_cc(compiler, type & ~(SLJIT_32 | SLJIT_COMPARE_SELECT));37713772if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) {3773tmp = get_imm((sljit_uw)src1w);3774if (tmp) {3775if (type & SLJIT_COMPARE_SELECT)3776FAIL_IF(push_inst(compiler, (CMP | SET_FLAGS | RN(dst_reg) | tmp)));3777return push_inst(compiler, ((MOV | RD(dst_reg) | tmp) & ~COND_MASK) | cc);3778}37793780tmp = get_imm(~(sljit_uw)src1w);3781if (tmp && (type & SLJIT_COMPARE_SELECT)) {3782tmp2 = get_imm((sljit_uw)-src1w);3783if (tmp2)3784FAIL_IF(push_inst(compiler, (CMN | SET_FLAGS | RN(dst_reg) | tmp2)));3785else3786tmp = 0;3787}37883789if (tmp)3790return push_inst(compiler, ((MVN | RD(dst_reg) | tmp) & ~COND_MASK) | cc);37913792#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)3793if (!(type & SLJIT_COMPARE_SELECT)) {3794tmp = (sljit_ins)src1w;3795FAIL_IF(push_inst(compiler, (MOVW & ~COND_MASK) | cc | RD(dst_reg) | ((tmp << 4) & 0xf0000) | (tmp & 0xfff)));3796if (tmp <= 0xffff)3797return SLJIT_SUCCESS;3798return push_inst(compiler, (MOVT & ~COND_MASK) | cc | RD(dst_reg) | ((tmp >> 12) & 0xf0000) | ((tmp >> 16) & 0xfff));3799}3800#endif /* SLJIT_CONFIG_ARM_V7 */38013802FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));3803src1 = TMP_REG1;3804}38053806if (type & SLJIT_COMPARE_SELECT)3807FAIL_IF(push_inst(compiler, (CMP | SET_FLAGS | RN(dst_reg) | RM(src1))));38083809return push_inst(compiler, ((MOV | RD(dst_reg) | RM(src1)) & ~COND_MASK) | cc);3810}38113812SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,3813sljit_s32 dst_freg,3814sljit_s32 src1, sljit_sw src1w,3815sljit_s32 src2_freg)3816{3817sljit_ins cc;38183819CHECK_ERROR();3820CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));38213822ADJUST_LOCAL_OFFSET(src1, src1w);38233824type ^= SLJIT_32;38253826if (dst_freg != src2_freg) {3827if (dst_freg == src1) {3828src1 = src2_freg;3829src1w = 0;3830type ^= 0x1;3831} else3832FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, (type & SLJIT_32), dst_freg, src2_freg, 0)));3833}38343835if (src1 & SLJIT_MEM) {3836FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) | FPU_LOAD, TMP_FREG2, src1, src1w));3837src1 = TMP_FREG2;3838}38393840cc = get_cc(compiler, type & ~SLJIT_32);3841return push_inst(compiler, EMIT_FPU_OPERATION((VMOV_F32 & ~COND_MASK) | cc, (type & SLJIT_32), dst_freg, src1, 0));3842}38433844#undef EMIT_FPU_OPERATION38453846static sljit_s32 update_mem_addr(struct sljit_compiler *compiler, sljit_s32 *mem, sljit_sw *memw, sljit_s32 max_offset)3847{3848sljit_s32 arg = *mem;3849sljit_sw argw = *memw;3850sljit_uw imm, tmp;3851sljit_sw mask = 0xfff;3852sljit_sw sign = 0x1000;38533854SLJIT_ASSERT(max_offset >= 0xf00);38553856*mem = TMP_REG1;38573858if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {3859*memw = 0;3860return push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | ((sljit_ins)(argw & 0x3) << 7));3861}38623863arg &= REG_MASK;38643865if (arg) {3866if (argw <= max_offset && argw >= -mask) {3867*mem = arg;3868return SLJIT_SUCCESS;3869}38703871if (argw >= 0) {3872tmp = (sljit_uw)(argw & (sign | mask));3873tmp = (sljit_uw)((argw + ((tmp <= (sljit_uw)max_offset || tmp == (sljit_uw)sign) ? 0 : sign)) & ~mask);3874imm = get_imm(tmp);38753876if (imm) {3877*memw = argw - (sljit_sw)tmp;3878SLJIT_ASSERT(*memw >= -mask && *memw <= max_offset);38793880return push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg) | imm);3881}3882} else {3883tmp = (sljit_uw)(-argw & (sign | mask));3884tmp = (sljit_uw)((-argw + ((tmp <= (sljit_uw)((sign << 1) - max_offset - 1)) ? 0 : sign)) & ~mask);3885imm = get_imm(tmp);38863887if (imm) {3888*memw = argw + (sljit_sw)tmp;3889SLJIT_ASSERT(*memw >= -mask && *memw <= max_offset);38903891return push_inst(compiler, SUB | RD(TMP_REG1) | RN(arg) | imm);3892}3893}3894}38953896tmp = (sljit_uw)(argw & (sign | mask));3897tmp = (sljit_uw)((argw + ((tmp <= (sljit_uw)max_offset || tmp == (sljit_uw)sign) ? 0 : sign)) & ~mask);3898*memw = argw - (sljit_sw)tmp;38993900FAIL_IF(load_immediate(compiler, TMP_REG1, tmp));39013902if (arg == 0)3903return SLJIT_SUCCESS;39043905return push_inst(compiler, ADD | RD(TMP_REG1) | RN(TMP_REG1) | RM(arg));3906}39073908SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,3909sljit_s32 reg,3910sljit_s32 mem, sljit_sw memw)3911{3912sljit_s32 flags;39133914CHECK_ERROR();3915CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw));39163917if (!(reg & REG_PAIR_MASK))3918return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw);39193920ADJUST_LOCAL_OFFSET(mem, memw);39213922FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4));39233924flags = WORD_SIZE;39253926if (!(type & SLJIT_MEM_STORE)) {3927if (REG_PAIR_FIRST(reg) == (mem & REG_MASK)) {3928FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), memw + SSIZE_OF(sw), TMP_REG1));3929return emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw, TMP_REG1);3930}39313932flags = WORD_SIZE | LOAD_DATA;3933}39343935FAIL_IF(emit_op_mem(compiler, flags, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw, TMP_REG1));3936return emit_op_mem(compiler, flags, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), memw + SSIZE_OF(sw), TMP_REG1);3937}39383939SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *compiler, sljit_s32 type,3940sljit_s32 reg,3941sljit_s32 mem, sljit_sw memw)3942{3943sljit_s32 flags;3944sljit_ins is_type1_transfer, inst;39453946CHECK_ERROR();3947CHECK(check_sljit_emit_mem_update(compiler, type, reg, mem, memw));39483949is_type1_transfer = 1;39503951switch (type & 0xff) {3952case SLJIT_MOV:3953case SLJIT_MOV_U32:3954case SLJIT_MOV_S32:3955case SLJIT_MOV32:3956case SLJIT_MOV_P:3957flags = WORD_SIZE;3958break;3959case SLJIT_MOV_U8:3960flags = BYTE_SIZE;3961break;3962case SLJIT_MOV_S8:3963if (!(type & SLJIT_MEM_STORE))3964is_type1_transfer = 0;3965flags = BYTE_SIZE | SIGNED;3966break;3967case SLJIT_MOV_U16:3968is_type1_transfer = 0;3969flags = HALF_SIZE;3970break;3971case SLJIT_MOV_S16:3972is_type1_transfer = 0;3973flags = HALF_SIZE | SIGNED;3974break;3975default:3976SLJIT_UNREACHABLE();3977flags = WORD_SIZE;3978break;3979}39803981if (!(type & SLJIT_MEM_STORE))3982flags |= LOAD_DATA;39833984SLJIT_ASSERT(is_type1_transfer == !!IS_TYPE1_TRANSFER(flags));39853986if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {3987if (!is_type1_transfer && memw != 0)3988return SLJIT_ERR_UNSUPPORTED;3989} else {3990if (is_type1_transfer) {3991if (memw > 4095 || memw < -4095)3992return SLJIT_ERR_UNSUPPORTED;3993} else if (memw > 255 || memw < -255)3994return SLJIT_ERR_UNSUPPORTED;3995}39963997if (type & SLJIT_MEM_SUPP)3998return SLJIT_SUCCESS;39994000if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {4001memw &= 0x3;40024003inst = EMIT_DATA_TRANSFER(flags, 1, reg, mem & REG_MASK, RM(OFFS_REG(mem)) | ((sljit_ins)memw << 7));40044005if (is_type1_transfer)4006inst |= (1 << 25);40074008if (type & SLJIT_MEM_POST)4009inst ^= (1 << 24);4010else4011inst |= (1 << 21);40124013return push_inst(compiler, inst);4014}40154016inst = EMIT_DATA_TRANSFER(flags, 0, reg, mem & REG_MASK, 0);40174018if (type & SLJIT_MEM_POST)4019inst ^= (1 << 24);4020else4021inst |= (1 << 21);40224023if (is_type1_transfer) {4024if (memw >= 0)4025inst |= (1 << 23);4026else4027memw = -memw;40284029return push_inst(compiler, inst | (sljit_ins)memw);4030}40314032if (memw >= 0)4033inst |= (1 << 23);4034else4035memw = -memw;40364037return push_inst(compiler, inst | TYPE2_TRANSFER_IMM((sljit_ins)memw));4038}40394040SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type,4041sljit_s32 freg,4042sljit_s32 mem, sljit_sw memw)4043{4044CHECK_ERROR();4045CHECK(check_sljit_emit_fmem(compiler, type, freg, mem, memw));40464047if (type & SLJIT_MEM_ALIGNED_32)4048return emit_fop_mem(compiler, ((type ^ SLJIT_32) & SLJIT_32) | ((type & SLJIT_MEM_STORE) ? 0 : FPU_LOAD), freg, mem, memw);40494050if (type & SLJIT_MEM_STORE) {4051FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(freg) | RD(TMP_REG2)));40524053if (type & SLJIT_32)4054return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1);40554056FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4));4057mem |= SLJIT_MEM;40584059FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1));4060FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(freg) | 0x80 | RD(TMP_REG2)));4061return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw + 4, TMP_REG1);4062}40634064if (type & SLJIT_32) {4065FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, mem, memw, TMP_REG1));4066return push_inst(compiler, VMOV | VN(freg) | RD(TMP_REG2));4067}40684069FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4));4070mem |= SLJIT_MEM;40714072FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, mem, memw, TMP_REG1));4073FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, mem, memw + 4, TMP_REG1));4074return push_inst(compiler, VMOV2 | VM(freg) | RD(TMP_REG2) | RN(TMP_REG1));4075}40764077static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, sljit_s32 *mem_ptr, sljit_sw memw)4078{4079sljit_s32 mem = *mem_ptr;4080sljit_uw imm;40814082if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {4083*mem_ptr = TMP_REG1;4084return push_inst(compiler, ADD | RD(TMP_REG1) | RN(mem & REG_MASK) | RM(OFFS_REG(mem)) | ((sljit_ins)(memw & 0x3) << 7));4085}40864087if (SLJIT_UNLIKELY(!(mem & REG_MASK))) {4088*mem_ptr = TMP_REG1;4089return load_immediate(compiler, TMP_REG1, (sljit_uw)memw);4090}40914092mem &= REG_MASK;40934094if (memw == 0) {4095*mem_ptr = mem;4096return SLJIT_SUCCESS;4097}40984099*mem_ptr = TMP_REG1;4100imm = get_imm((sljit_uw)(memw < 0 ? -memw : memw));41014102if (imm != 0)4103return push_inst(compiler, ((memw < 0) ? SUB : ADD) | RD(TMP_REG1) | RN(mem) | imm);41044105FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)memw));4106return push_inst(compiler, ADD | RD(TMP_REG1) | RN(TMP_REG1) | RM(mem));4107}41084109static SLJIT_INLINE sljit_s32 simd_get_quad_reg_index(sljit_s32 freg)4110{4111freg += freg & 0x1;41124113SLJIT_ASSERT((freg_map[freg] & 0x1) == (freg <= SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS));41144115if (freg <= SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS)4116freg--;41174118return freg;4119}41204121#define SLJIT_QUAD_OTHER_HALF(freg) ((((freg) & 0x1) << 1) - 1)41224123SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,4124sljit_s32 vreg,4125sljit_s32 srcdst, sljit_sw srcdstw)4126{4127sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);4128sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);4129sljit_s32 alignment = SLJIT_SIMD_GET_ELEM2_SIZE(type);4130sljit_ins ins;41314132CHECK_ERROR();4133CHECK(check_sljit_emit_simd_mov(compiler, type, vreg, srcdst, srcdstw));41344135ADJUST_LOCAL_OFFSET(srcdst, srcdstw);41364137if (reg_size != 3 && reg_size != 4)4138return SLJIT_ERR_UNSUPPORTED;41394140if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))4141return SLJIT_ERR_UNSUPPORTED;41424143if (type & SLJIT_SIMD_TEST)4144return SLJIT_SUCCESS;41454146if (reg_size == 4)4147vreg = simd_get_quad_reg_index(vreg);41484149if (!(srcdst & SLJIT_MEM)) {4150if (reg_size == 4)4151srcdst = simd_get_quad_reg_index(srcdst);41524153if (type & SLJIT_SIMD_STORE)4154ins = VD(srcdst) | VN(vreg) | VM(vreg);4155else4156ins = VD(vreg) | VN(srcdst) | VM(srcdst);41574158if (reg_size == 4)4159ins |= (sljit_ins)1 << 6;41604161return push_inst(compiler, VORR | ins);4162}41634164FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw));41654166if (elem_size > 3)4167elem_size = 3;41684169ins = ((type & SLJIT_SIMD_STORE) ? VST1 : VLD1) | VD(vreg)4170| (sljit_ins)((reg_size == 3) ? (0x7 << 8) : (0xa << 8));41714172SLJIT_ASSERT(reg_size >= alignment);41734174if (alignment == 3)4175ins |= 0x10;4176else if (alignment >= 3)4177ins |= 0x20;41784179return push_inst(compiler, ins | RN(srcdst) | ((sljit_ins)elem_size) << 6 | 0xf);4180}41814182static sljit_ins simd_get_imm(sljit_s32 elem_size, sljit_uw value)4183{4184sljit_ins result;41854186if (elem_size > 1 && (sljit_u16)value == (value >> 16)) {4187elem_size = 1;4188value = (sljit_u16)value;4189}41904191if (elem_size == 1 && (sljit_u8)value == (value >> 8)) {4192elem_size = 0;4193value = (sljit_u8)value;4194}41954196switch (elem_size) {4197case 0:4198SLJIT_ASSERT(value <= 0xff);4199result = 0xe00;4200break;4201case 1:4202SLJIT_ASSERT(value <= 0xffff);4203result = 0;42044205while (1) {4206if (value <= 0xff) {4207result |= 0x800;4208break;4209}42104211if ((value & 0xff) == 0) {4212value >>= 8;4213result |= 0xa00;4214break;4215}42164217if (result != 0)4218return ~(sljit_ins)0;42194220value ^= (sljit_uw)0xffff;4221result = (1 << 5);4222}4223break;4224default:4225SLJIT_ASSERT(value <= 0xffffffff);4226result = 0;42274228while (1) {4229if (value <= 0xff) {4230result |= 0x000;4231break;4232}42334234if ((value & ~(sljit_uw)0xff00) == 0) {4235value >>= 8;4236result |= 0x200;4237break;4238}42394240if ((value & ~(sljit_uw)0xff0000) == 0) {4241value >>= 16;4242result |= 0x400;4243break;4244}42454246if ((value & ~(sljit_uw)0xff000000) == 0) {4247value >>= 24;4248result |= 0x600;4249break;4250}42514252if ((value & (sljit_uw)0xff) == 0xff && (value >> 16) == 0) {4253value >>= 8;4254result |= 0xc00;4255break;4256}42574258if ((value & (sljit_uw)0xffff) == 0xffff && (value >> 24) == 0) {4259value >>= 16;4260result |= 0xd00;4261break;4262}42634264if (result != 0)4265return ~(sljit_ins)0;42664267value = ~value;4268result = (1 << 5);4269}4270break;4271}42724273return ((sljit_ins)value & 0xf) | (((sljit_ins)value & 0x70) << 12) | (((sljit_ins)value & 0x80) << 17) | result;4274}42754276SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compiler *compiler, sljit_s32 type,4277sljit_s32 vreg,4278sljit_s32 src, sljit_sw srcw)4279{4280sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);4281sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);4282sljit_ins ins, imm;42834284CHECK_ERROR();4285CHECK(check_sljit_emit_simd_replicate(compiler, type, vreg, src, srcw));42864287ADJUST_LOCAL_OFFSET(src, srcw);42884289if (reg_size != 3 && reg_size != 4)4290return SLJIT_ERR_UNSUPPORTED;42914292if ((type & SLJIT_SIMD_FLOAT) ? (elem_size < 2 || elem_size > 3) : (elem_size > 2))4293return SLJIT_ERR_UNSUPPORTED;42944295if (type & SLJIT_SIMD_TEST)4296return SLJIT_SUCCESS;42974298if (reg_size == 4)4299vreg = simd_get_quad_reg_index(vreg);43004301if (src == SLJIT_IMM && srcw == 0)4302return push_inst(compiler, VMOV_i | ((reg_size == 4) ? (1 << 6) : 0) | VD(vreg));43034304if (SLJIT_UNLIKELY(elem_size == 3)) {4305SLJIT_ASSERT(type & SLJIT_SIMD_FLOAT);43064307if (src & SLJIT_MEM) {4308FAIL_IF(emit_fop_mem(compiler, FPU_LOAD | SLJIT_32, vreg, src, srcw));4309src = vreg;4310} else if (vreg != src)4311FAIL_IF(push_inst(compiler, VORR | VD(vreg) | VN(src) | VM(src)));43124313vreg += SLJIT_QUAD_OTHER_HALF(vreg);43144315if (vreg != src)4316return push_inst(compiler, VORR | VD(vreg) | VN(src) | VM(src));4317return SLJIT_SUCCESS;4318}43194320if (src & SLJIT_MEM) {4321FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw));43224323ins = (sljit_ins)(elem_size << 6);43244325if (reg_size == 4)4326ins |= (sljit_ins)1 << 5;43274328return push_inst(compiler, VLD1_r | ins | VD(vreg) | RN(src) | 0xf);4329}43304331if (type & SLJIT_SIMD_FLOAT) {4332SLJIT_ASSERT(elem_size == 2);4333ins = ((sljit_ins)freg_ebit_map[src] << (16 + 2 + 1)) | ((sljit_ins)1 << (16 + 2));43344335if (reg_size == 4)4336ins |= (sljit_ins)1 << 6;43374338return push_inst(compiler, VDUP_s | ins | VD(vreg) | (sljit_ins)freg_map[src]);4339}43404341if (src == SLJIT_IMM) {4342if (elem_size < 2)4343srcw &= ((sljit_sw)1 << (((sljit_sw)1 << elem_size) << 3)) - 1;43444345imm = simd_get_imm(elem_size, (sljit_uw)srcw);43464347if (imm != ~(sljit_ins)0) {4348if (reg_size == 4)4349imm |= (sljit_ins)1 << 6;43504351return push_inst(compiler, VMOV_i | imm | VD(vreg));4352}43534354FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcw));4355src = TMP_REG1;4356}43574358switch (elem_size) {4359case 0:4360ins = 1 << 22;4361break;4362case 1:4363ins = 1 << 5;4364break;4365default:4366ins = 0;4367break;4368}43694370if (reg_size == 4)4371ins |= (sljit_ins)1 << 21;43724373return push_inst(compiler, VDUP | ins | VN(vreg) | RD(src));4374}43754376SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compiler *compiler, sljit_s32 type,4377sljit_s32 vreg, sljit_s32 lane_index,4378sljit_s32 srcdst, sljit_sw srcdstw)4379{4380sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);4381sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);4382sljit_ins ins;43834384CHECK_ERROR();4385CHECK(check_sljit_emit_simd_lane_mov(compiler, type, vreg, lane_index, srcdst, srcdstw));43864387ADJUST_LOCAL_OFFSET(srcdst, srcdstw);43884389if (reg_size != 3 && reg_size != 4)4390return SLJIT_ERR_UNSUPPORTED;43914392if ((type & SLJIT_SIMD_FLOAT) ? (elem_size < 2 || elem_size > 3) : (elem_size > 2))4393return SLJIT_ERR_UNSUPPORTED;43944395if (type & SLJIT_SIMD_TEST)4396return SLJIT_SUCCESS;43974398if (reg_size == 4)4399vreg = simd_get_quad_reg_index(vreg);44004401if (type & SLJIT_SIMD_LANE_ZERO) {4402ins = (reg_size == 3) ? 0 : ((sljit_ins)1 << 6);44034404if (type & SLJIT_SIMD_FLOAT) {4405if (elem_size == 3 && !(srcdst & SLJIT_MEM)) {4406if (lane_index == 1)4407vreg += SLJIT_QUAD_OTHER_HALF(vreg);44084409if (srcdst != vreg)4410FAIL_IF(push_inst(compiler, VORR | VD(vreg) | VN(srcdst) | VM(srcdst)));44114412vreg += SLJIT_QUAD_OTHER_HALF(vreg);4413return push_inst(compiler, VMOV_i | VD(vreg));4414}44154416if (srcdst == vreg || (elem_size == 3 && srcdst == (vreg + SLJIT_QUAD_OTHER_HALF(vreg)))) {4417FAIL_IF(push_inst(compiler, VORR | ins | VD(TMP_FREG2) | VN(vreg) | VM(vreg)));4418srcdst = TMP_FREG2;4419srcdstw = 0;4420}4421}44224423FAIL_IF(push_inst(compiler, VMOV_i | ins | VD(vreg)));4424}44254426if (reg_size == 4 && lane_index >= (0x8 >> elem_size)) {4427lane_index -= (0x8 >> elem_size);4428vreg += SLJIT_QUAD_OTHER_HALF(vreg);4429}44304431if (srcdst & SLJIT_MEM) {4432if (elem_size == 3)4433return emit_fop_mem(compiler, ((type & SLJIT_SIMD_STORE) ? 0 : FPU_LOAD) | SLJIT_32, vreg, srcdst, srcdstw);44344435FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw));44364437lane_index = lane_index << elem_size;4438ins = (sljit_ins)((elem_size << 10) | (lane_index << 5));4439return push_inst(compiler, ((type & SLJIT_SIMD_STORE) ? VST1_s : VLD1_s) | ins | VD(vreg) | RN(srcdst) | 0xf);4440}44414442if (type & SLJIT_SIMD_FLOAT) {4443if (elem_size == 3) {4444if (type & SLJIT_SIMD_STORE)4445return push_inst(compiler, VORR | VD(srcdst) | VN(vreg) | VM(vreg));4446return push_inst(compiler, VMOV_F32 | SLJIT_32 | VD(vreg) | VM(srcdst));4447}44484449if (type & SLJIT_SIMD_STORE) {4450if (freg_ebit_map[vreg] == 0) {4451if (lane_index == 1)4452vreg = SLJIT_F64_SECOND(vreg);44534454return push_inst(compiler, VMOV_F32 | VD(srcdst) | VM(vreg));4455}44564457FAIL_IF(push_inst(compiler, VMOV_s | (1 << 20) | ((sljit_ins)lane_index << 21) | VN(vreg) | RD(TMP_REG1)));4458return push_inst(compiler, VMOV | VN(srcdst) | RD(TMP_REG1));4459}44604461FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(srcdst) | RD(TMP_REG1)));4462return push_inst(compiler, VMOV_s | ((sljit_ins)lane_index << 21) | VN(vreg) | RD(TMP_REG1));4463}44644465if (srcdst == SLJIT_IMM) {4466if (elem_size < 2)4467srcdstw &= ((sljit_sw)1 << (((sljit_sw)1 << elem_size) << 3)) - 1;44684469FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcdstw));4470srcdst = TMP_REG1;4471}44724473if (elem_size == 0)4474ins = 0x400000;4475else if (elem_size == 1)4476ins = 0x20;4477else4478ins = 0;44794480lane_index = lane_index << elem_size;4481ins |= (sljit_ins)(((lane_index & 0x4) << 19) | ((lane_index & 0x3) << 5));44824483if (type & SLJIT_SIMD_STORE) {4484ins |= (1 << 20);44854486if (elem_size < 2 && !(type & SLJIT_SIMD_LANE_SIGNED))4487ins |= (1 << 23);4488}44894490return push_inst(compiler, VMOV_s | ins | VN(vreg) | RD(srcdst));4491}44924493SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_compiler *compiler, sljit_s32 type,4494sljit_s32 vreg,4495sljit_s32 src, sljit_s32 src_lane_index)4496{4497sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);4498sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);4499sljit_ins ins;45004501CHECK_ERROR();4502CHECK(check_sljit_emit_simd_lane_replicate(compiler, type, vreg, src, src_lane_index));45034504if (reg_size != 3 && reg_size != 4)4505return SLJIT_ERR_UNSUPPORTED;45064507if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))4508return SLJIT_ERR_UNSUPPORTED;45094510if (type & SLJIT_SIMD_TEST)4511return SLJIT_SUCCESS;45124513if (reg_size == 4) {4514vreg = simd_get_quad_reg_index(vreg);4515src = simd_get_quad_reg_index(src);45164517if (src_lane_index >= (0x8 >> elem_size)) {4518src_lane_index -= (0x8 >> elem_size);4519src += SLJIT_QUAD_OTHER_HALF(src);4520}4521}45224523if (elem_size == 3) {4524if (vreg != src)4525FAIL_IF(push_inst(compiler, VORR | VD(vreg) | VN(src) | VM(src)));45264527vreg += SLJIT_QUAD_OTHER_HALF(vreg);45284529if (vreg != src)4530return push_inst(compiler, VORR | VD(vreg) | VN(src) | VM(src));4531return SLJIT_SUCCESS;4532}45334534ins = ((((sljit_ins)src_lane_index << 1) | 1) << (16 + elem_size));45354536if (reg_size == 4)4537ins |= (sljit_ins)1 << 6;45384539return push_inst(compiler, VDUP_s | ins | VD(vreg) | VM(src));4540}45414542SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler *compiler, sljit_s32 type,4543sljit_s32 vreg,4544sljit_s32 src, sljit_sw srcw)4545{4546sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);4547sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);4548sljit_s32 elem2_size = SLJIT_SIMD_GET_ELEM2_SIZE(type);4549sljit_s32 dst_reg;45504551CHECK_ERROR();4552CHECK(check_sljit_emit_simd_extend(compiler, type, vreg, src, srcw));45534554ADJUST_LOCAL_OFFSET(src, srcw);45554556if (reg_size != 3 && reg_size != 4)4557return SLJIT_ERR_UNSUPPORTED;45584559if ((type & SLJIT_SIMD_FLOAT) && (elem_size != 2 || elem2_size != 3))4560return SLJIT_ERR_UNSUPPORTED;45614562if (type & SLJIT_SIMD_TEST)4563return SLJIT_SUCCESS;45644565if (reg_size == 4)4566vreg = simd_get_quad_reg_index(vreg);45674568if (src & SLJIT_MEM) {4569FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw));4570if (reg_size == 4 && elem2_size - elem_size == 1)4571FAIL_IF(push_inst(compiler, VLD1 | (0x7 << 8) | VD(vreg) | RN(src) | 0xf));4572else4573FAIL_IF(push_inst(compiler, VLD1_s | (sljit_ins)((reg_size - elem2_size + elem_size) << 10) | VD(vreg) | RN(src) | 0xf));4574src = vreg;4575} else if (reg_size == 4)4576src = simd_get_quad_reg_index(src);45774578if (!(type & SLJIT_SIMD_FLOAT)) {4579dst_reg = (reg_size == 4) ? vreg : TMP_FREG2;45804581do {4582FAIL_IF(push_inst(compiler, VSHLL | ((type & SLJIT_SIMD_EXTEND_SIGNED) ? 0 : (1 << 24))4583| ((sljit_ins)1 << (19 + elem_size)) | VD(dst_reg) | VM(src)));4584src = dst_reg;4585} while (++elem_size < elem2_size);45864587if (dst_reg == TMP_FREG2)4588return push_inst(compiler, VORR | VD(vreg) | VN(TMP_FREG2) | VM(TMP_FREG2));4589return SLJIT_SUCCESS;4590}45914592/* No SIMD variant, must use VFP instead. */4593SLJIT_ASSERT(reg_size == 4);45944595if (vreg == src) {4596vreg += SLJIT_QUAD_OTHER_HALF(vreg);4597FAIL_IF(push_inst(compiler, VCVT_F64_F32 | VD(vreg) | VM(src) | 0x20));4598vreg += SLJIT_QUAD_OTHER_HALF(vreg);4599return push_inst(compiler, VCVT_F64_F32 | VD(vreg) | VM(src));4600}46014602FAIL_IF(push_inst(compiler, VCVT_F64_F32 | VD(vreg) | VM(src)));4603vreg += SLJIT_QUAD_OTHER_HALF(vreg);4604return push_inst(compiler, VCVT_F64_F32 | VD(vreg) | VM(src) | 0x20);4605}46064607SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type,4608sljit_s32 vreg,4609sljit_s32 dst, sljit_sw dstw)4610{4611sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);4612sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);4613sljit_ins ins, imms;4614sljit_s32 dst_r;46154616CHECK_ERROR();4617CHECK(check_sljit_emit_simd_sign(compiler, type, vreg, dst, dstw));46184619ADJUST_LOCAL_OFFSET(dst, dstw);46204621if (reg_size != 3 && reg_size != 4)4622return SLJIT_ERR_UNSUPPORTED;46234624if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))4625return SLJIT_ERR_UNSUPPORTED;46264627if (type & SLJIT_SIMD_TEST)4628return SLJIT_SUCCESS;46294630switch (elem_size) {4631case 0:4632imms = 0x243219;4633ins = VSHR | (1 << 24) | (0x9 << 16);4634break;4635case 1:4636imms = (reg_size == 4) ? 0x243219 : 0x2231;4637ins = VSHR | (1 << 24) | (0x11 << 16);4638break;4639case 2:4640imms = (reg_size == 4) ? 0x2231 : 0x21;4641ins = VSHR | (1 << 24) | (0x21 << 16);4642break;4643default:4644imms = 0x21;4645ins = VSHR | (1 << 24) | (0x1 << 16) | (1 << 7);4646break;4647}46484649if (reg_size == 4) {4650vreg = simd_get_quad_reg_index(vreg);4651ins |= (sljit_ins)1 << 6;4652}46534654SLJIT_ASSERT((freg_map[TMP_FREG2] & 0x1) == 0);4655FAIL_IF(push_inst(compiler, ins | VD(TMP_FREG2) | VM(vreg)));46564657if (reg_size == 4 && elem_size > 0)4658FAIL_IF(push_inst(compiler, VMOVN | ((sljit_ins)(elem_size - 1) << 18) | VD(TMP_FREG2) | VM(TMP_FREG2)));46594660ins = (reg_size == 4 && elem_size == 0) ? (1 << 6) : 0;46614662while (imms >= 0x100) {4663FAIL_IF(push_inst(compiler, VSRA | (1 << 24) | ins | ((imms & 0xff) << 16) | VD(TMP_FREG2) | VM(TMP_FREG2)));4664imms >>= 8;4665}46664667FAIL_IF(push_inst(compiler, VSRA | (1 << 24) | ins | (1 << 7) | (imms << 16) | VD(TMP_FREG2) | VM(TMP_FREG2)));46684669dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;4670FAIL_IF(push_inst(compiler, VMOV_s | (1 << 20) | (1 << 23) | (0x2 << 21) | RD(dst_r) | VN(TMP_FREG2)));46714672if (reg_size == 4 && elem_size == 0) {4673SLJIT_ASSERT(freg_map[TMP_FREG2] + 1 == freg_map[TMP_FREG1]);4674FAIL_IF(push_inst(compiler, VMOV_s | (1 << 20) | (1 << 23) | (0x2 << 21) | RD(TMP_REG2) | VN(TMP_FREG1)));4675FAIL_IF(push_inst(compiler, ORR | RD(dst_r) | RN(dst_r) | RM(TMP_REG2) | (0x8 << 7)));4676}46774678if (dst_r == TMP_REG1)4679return emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2);46804681return SLJIT_SUCCESS;4682}46834684SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *compiler, sljit_s32 type,4685sljit_s32 dst_vreg, sljit_s32 src1_vreg, sljit_s32 src2, sljit_sw src2w)4686{4687sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);4688sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);4689sljit_s32 alignment;4690sljit_ins ins = 0, load_ins;46914692CHECK_ERROR();4693CHECK(check_sljit_emit_simd_op2(compiler, type, dst_vreg, src1_vreg, src2, src2w));4694ADJUST_LOCAL_OFFSET(src2, src2w);46954696if (reg_size != 3 && reg_size != 4)4697return SLJIT_ERR_UNSUPPORTED;46984699if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))4700return SLJIT_ERR_UNSUPPORTED;47014702if (type & SLJIT_SIMD_TEST)4703return SLJIT_SUCCESS;47044705switch (SLJIT_SIMD_GET_OPCODE(type)) {4706case SLJIT_SIMD_OP2_AND:4707ins = VAND;4708break;4709case SLJIT_SIMD_OP2_OR:4710ins = VORR;4711break;4712case SLJIT_SIMD_OP2_XOR:4713ins = VEOR;4714break;4715case SLJIT_SIMD_OP2_SHUFFLE:4716ins = VTBL;4717break;4718}47194720if (src2 & SLJIT_MEM) {4721if (elem_size > 3)4722elem_size = 3;47234724load_ins = VLD1 | (sljit_ins)((reg_size == 3) ? (0x7 << 8) : (0xa << 8));4725alignment = SLJIT_SIMD_GET_ELEM2_SIZE(type);47264727SLJIT_ASSERT(reg_size >= alignment);47284729if (alignment == 3)4730load_ins |= 0x10;4731else if (alignment >= 4)4732load_ins |= 0x20;47334734FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src2, src2w));4735FAIL_IF(push_inst(compiler, load_ins | VD(TMP_FREG2) | RN(src2) | ((sljit_ins)elem_size) << 6 | 0xf));4736src2 = TMP_FREG2;4737}47384739if (reg_size == 4) {4740dst_vreg = simd_get_quad_reg_index(dst_vreg);4741src1_vreg = simd_get_quad_reg_index(src1_vreg);4742src2 = simd_get_quad_reg_index(src2);47434744if (SLJIT_SIMD_GET_OPCODE(type) == SLJIT_SIMD_OP2_SHUFFLE) {4745ins |= (sljit_ins)1 << 8;47464747FAIL_IF(push_inst(compiler, ins | VD(dst_vreg != src1_vreg ? dst_vreg : TMP_FREG2) | VN(src1_vreg) | VM(src2)));4748src2 += SLJIT_QUAD_OTHER_HALF(src2);4749FAIL_IF(push_inst(compiler, ins | VD(dst_vreg + SLJIT_QUAD_OTHER_HALF(dst_vreg)) | VN(src1_vreg) | VM(src2)));47504751if (dst_vreg == src1_vreg)4752return push_inst(compiler, VORR | VD(dst_vreg) | VN(TMP_FREG2) | VM(TMP_FREG2));4753return SLJIT_SUCCESS;4754}47554756ins |= (sljit_ins)1 << 6;4757}47584759return push_inst(compiler, ins | VD(dst_vreg) | VN(src1_vreg) | VM(src2));4760}47614762#undef FPU_LOAD47634764SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler, sljit_s32 op,4765sljit_s32 dst_reg,4766sljit_s32 mem_reg)4767{4768sljit_u32 ins;47694770CHECK_ERROR();4771CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg));47724773if (op & SLJIT_ATOMIC_USE_CAS)4774return SLJIT_ERR_UNSUPPORTED;47754776switch (GET_OPCODE(op)) {4777case SLJIT_MOV_S8:4778case SLJIT_MOV_S16:4779case SLJIT_MOV_S32:4780return SLJIT_ERR_UNSUPPORTED;47814782case SLJIT_MOV_U8:4783ins = LDREXB;4784break;4785case SLJIT_MOV_U16:4786ins = LDREXH;4787break;4788default:4789ins = LDREX;4790break;4791}47924793if (op & SLJIT_ATOMIC_TEST)4794return SLJIT_SUCCESS;47954796return push_inst(compiler, ins | RN(mem_reg) | RD(dst_reg));4797}47984799SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler, sljit_s32 op,4800sljit_s32 src_reg,4801sljit_s32 mem_reg,4802sljit_s32 temp_reg)4803{4804sljit_u32 ins;48054806/* temp_reg == mem_reg is undefined so use another temp register */4807SLJIT_UNUSED_ARG(temp_reg);48084809CHECK_ERROR();4810CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg));48114812if (op & SLJIT_ATOMIC_USE_CAS)4813return SLJIT_ERR_UNSUPPORTED;48144815switch (GET_OPCODE(op)) {4816case SLJIT_MOV_S8:4817case SLJIT_MOV_S16:4818case SLJIT_MOV_S32:4819return SLJIT_ERR_UNSUPPORTED;48204821case SLJIT_MOV_U8:4822ins = STREXB;4823break;4824case SLJIT_MOV_U16:4825ins = STREXH;4826break;4827default:4828ins = STREX;4829break;4830}48314832if (op & SLJIT_ATOMIC_TEST)4833return SLJIT_SUCCESS;48344835FAIL_IF(push_inst(compiler, ins | RN(mem_reg) | RD(TMP_REG1) | RM(src_reg)));4836if (op & SLJIT_SET_ATOMIC_STORED)4837return push_inst(compiler, CMP | SET_FLAGS | SRC2_IMM | RN(TMP_REG1));48384839return SLJIT_SUCCESS;4840}48414842#define SLJIT_EMIT_CONST_U8(c) \4843(((c) & 0x100) != 0 ? (MVN | SRC2_IMM | (~(c) & 0xff)) : (MOV | SRC2_IMM | ((c) & 0xff)))48444845SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,4846sljit_s32 dst, sljit_sw dstw,4847sljit_sw init_value)4848{4849struct sljit_const *const_;4850sljit_s32 dst_r;4851sljit_s32 mem_flags = WORD_SIZE;48524853CHECK_ERROR_PTR();4854CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));4855ADJUST_LOCAL_OFFSET(dst, dstw);48564857const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));4858PTR_FAIL_IF(!const_);4859set_const(const_, compiler);48604861dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;48624863if (GET_OPCODE(op) == SLJIT_MOV_U8) {4864PTR_FAIL_IF(push_inst(compiler, SLJIT_EMIT_CONST_U8(init_value) | RD(dst_r)));4865mem_flags = BYTE_SIZE;4866} else {4867#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)4868PTR_FAIL_IF(push_inst_with_unique_literal(compiler,4869EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), (sljit_ins)init_value));4870compiler->patches++;4871#else /* !SLJIT_CONFIG_ARM_V6 */4872PTR_FAIL_IF(emit_imm(compiler, dst_r, init_value));4873#endif /* SLJIT_CONFIG_ARM_V6 */4874}48754876if (dst & SLJIT_MEM)4877PTR_FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG2, dst, dstw, TMP_REG1));48784879return const_;4880}48814882SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,4883sljit_s32 dst, sljit_sw dstw)4884{4885struct sljit_jump *jump;4886sljit_s32 dst_r, target_r;4887SLJIT_UNUSED_ARG(op);48884889CHECK_ERROR_PTR();4890CHECK_PTR(check_sljit_emit_op_addr(compiler, op, dst, dstw));4891ADJUST_LOCAL_OFFSET(dst, dstw);48924893dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;48944895if (op != SLJIT_ADD_ABS_ADDR)4896target_r = dst_r;4897else {4898target_r = TMP_REG1;48994900if (dst & SLJIT_MEM)4901PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, dst, dstw, TMP_REG1));4902}49034904#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)4905PTR_FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, target_r, TMP_PC, 0), 0));4906compiler->patches++;4907#else /* !SLJIT_CONFIG_ARM_V6 */4908PTR_FAIL_IF(push_inst(compiler, RD(target_r)));4909#endif /* SLJIT_CONFIG_ARM_V6 */49104911jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));4912PTR_FAIL_IF(!jump);4913set_mov_addr(jump, compiler, 1);49144915#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)4916compiler->size += 1;4917#endif /* SLJIT_CONFIG_ARM_V7 */49184919if (op == SLJIT_ADD_ABS_ADDR)4920PTR_FAIL_IF(push_inst(compiler, ADD | RD(dst_r) | RN(dst_r) | RM(TMP_REG1)));49214922if (dst & SLJIT_MEM)4923PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1));4924return jump;4925}49264927SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)4928{4929set_jump_addr(addr, executable_offset, new_target, 1);4930}49314932SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)4933{4934sljit_ins *inst;49354936if (GET_OPCODE(op) != SLJIT_MOV_U8) {4937set_const_value(addr, executable_offset, (sljit_uw)new_constant, 1);4938return;4939}49404941inst = (sljit_ins*)addr;4942SLJIT_ASSERT((inst[0] & 0xfff00000) == (MOV | SRC2_IMM) || (inst[0] & 0xfff00000) == (MVN | SRC2_IMM));49434944SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);4945*inst = SLJIT_EMIT_CONST_U8(new_constant) | (*inst & 0xf000);4946SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);4947inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);4948SLJIT_CACHE_FLUSH(inst, inst + 1);4949}495049514952