11.4Salnsn/* $NetBSD: sljitNativeARM_T2_32.c,v 1.4 2019/01/20 23:14:16 alnsn Exp $ */ 21.2Salnsn 31.1Salnsn/* 41.1Salnsn * Stack-less Just-In-Time compiler 51.1Salnsn * 61.4Salnsn * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. 71.1Salnsn * 81.1Salnsn * Redistribution and use in source and binary forms, with or without modification, are 91.1Salnsn * permitted provided that the following conditions are met: 101.1Salnsn * 111.1Salnsn * 1. Redistributions of source code must retain the above copyright notice, this list of 121.1Salnsn * conditions and the following disclaimer. 131.1Salnsn * 141.1Salnsn * 2. Redistributions in binary form must reproduce the above copyright notice, this list 151.1Salnsn * of conditions and the following disclaimer in the documentation and/or other materials 161.1Salnsn * provided with the distribution. 171.1Salnsn * 181.1Salnsn * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY 191.1Salnsn * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 201.1Salnsn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 211.1Salnsn * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 221.1Salnsn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 231.1Salnsn * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 241.1Salnsn * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 251.1Salnsn * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 261.1Salnsn * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 271.1Salnsn */ 281.1Salnsn 291.3SalnsnSLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void) 301.1Salnsn{ 311.1Salnsn return "ARM-Thumb2" SLJIT_CPUINFO; 321.1Salnsn} 331.1Salnsn 341.1Salnsn/* Length of an instruction word. */ 351.3Salnsntypedef sljit_u32 sljit_ins; 361.1Salnsn 371.1Salnsn/* Last register + 1. */ 381.3Salnsn#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) 391.3Salnsn#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) 401.4Salnsn#define TMP_PC (SLJIT_NUMBER_OF_REGISTERS + 4) 411.1Salnsn 421.1Salnsn#define TMP_FREG1 (0) 431.3Salnsn#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) 441.1Salnsn 451.1Salnsn/* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */ 461.4Salnsnstatic const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = { 471.4Salnsn 0, 0, 1, 2, 12, 11, 10, 9, 8, 7, 6, 5, 4, 13, 3, 14, 15 481.1Salnsn}; 491.1Salnsn 501.1Salnsn#define COPY_BITS(src, from, to, bits) \ 511.1Salnsn ((from >= to ? (src >> (from - to)) : (src << (to - from))) & (((1 << bits) - 1) << to)) 521.1Salnsn 531.1Salnsn/* Thumb16 encodings. */ 541.1Salnsn#define RD3(rd) (reg_map[rd]) 551.1Salnsn#define RN3(rn) (reg_map[rn] << 3) 561.1Salnsn#define RM3(rm) (reg_map[rm] << 6) 571.1Salnsn#define RDN3(rdn) (reg_map[rdn] << 8) 581.1Salnsn#define IMM3(imm) (imm << 6) 591.1Salnsn#define IMM8(imm) (imm) 601.1Salnsn 611.1Salnsn/* Thumb16 helpers. */ 621.1Salnsn#define SET_REGS44(rd, rn) \ 631.1Salnsn ((reg_map[rn] << 3) | (reg_map[rd] & 0x7) | ((reg_map[rd] & 0x8) << 4)) 641.1Salnsn#define IS_2_LO_REGS(reg1, reg2) \ 651.1Salnsn (reg_map[reg1] <= 7 && reg_map[reg2] <= 7) 661.1Salnsn#define IS_3_LO_REGS(reg1, reg2, reg3) \ 671.1Salnsn (reg_map[reg1] <= 7 && reg_map[reg2] <= 7 && reg_map[reg3] <= 7) 681.1Salnsn 691.1Salnsn/* Thumb32 encodings. */ 701.1Salnsn#define RD4(rd) (reg_map[rd] << 8) 711.1Salnsn#define RN4(rn) (reg_map[rn] << 16) 721.1Salnsn#define RM4(rm) (reg_map[rm]) 731.1Salnsn#define RT4(rt) (reg_map[rt] << 12) 741.1Salnsn#define DD4(dd) ((dd) << 12) 751.1Salnsn#define DN4(dn) ((dn) << 16) 761.1Salnsn#define DM4(dm) (dm) 771.1Salnsn#define IMM5(imm) \ 781.1Salnsn (COPY_BITS(imm, 2, 12, 3) | ((imm & 0x3) << 6)) 791.1Salnsn#define IMM12(imm) \ 801.1Salnsn (COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | (imm & 0xff)) 811.1Salnsn 821.1Salnsn/* --------------------------------------------------------------------- */ 831.1Salnsn/* Instrucion forms */ 841.1Salnsn/* --------------------------------------------------------------------- */ 851.1Salnsn 861.1Salnsn/* dot '.' changed to _ 871.1Salnsn I immediate form (possibly followed by number of immediate bits). */ 881.1Salnsn#define ADCI 0xf1400000 891.1Salnsn#define ADCS 0x4140 901.1Salnsn#define ADC_W 0xeb400000 911.1Salnsn#define ADD 0x4400 921.1Salnsn#define ADDS 0x1800 931.1Salnsn#define ADDSI3 0x1c00 941.1Salnsn#define ADDSI8 0x3000 951.1Salnsn#define ADD_W 0xeb000000 961.1Salnsn#define ADDWI 0xf2000000 971.1Salnsn#define ADD_SP 0xb000 981.1Salnsn#define ADD_W 0xeb000000 991.1Salnsn#define ADD_WI 0xf1000000 1001.1Salnsn#define ANDI 0xf0000000 1011.1Salnsn#define ANDS 0x4000 1021.1Salnsn#define AND_W 0xea000000 1031.1Salnsn#define ASRS 0x4100 1041.1Salnsn#define ASRSI 0x1000 1051.1Salnsn#define ASR_W 0xfa40f000 1061.1Salnsn#define ASR_WI 0xea4f0020 1071.1Salnsn#define BICI 0xf0200000 1081.1Salnsn#define BKPT 0xbe00 1091.1Salnsn#define BLX 0x4780 1101.1Salnsn#define BX 0x4700 1111.1Salnsn#define CLZ 0xfab0f080 1121.1Salnsn#define CMPI 0x2800 1131.1Salnsn#define CMP_W 0xebb00f00 1141.1Salnsn#define EORI 0xf0800000 1151.1Salnsn#define EORS 0x4040 1161.1Salnsn#define EOR_W 0xea800000 1171.1Salnsn#define IT 0xbf00 1181.1Salnsn#define LSLS 0x4080 1191.1Salnsn#define LSLSI 0x0000 1201.1Salnsn#define LSL_W 0xfa00f000 1211.1Salnsn#define LSL_WI 0xea4f0000 1221.1Salnsn#define LSRS 0x40c0 1231.1Salnsn#define LSRSI 0x0800 1241.1Salnsn#define LSR_W 0xfa20f000 1251.1Salnsn#define LSR_WI 0xea4f0010 1261.1Salnsn#define MOV 0x4600 1271.1Salnsn#define MOVS 0x0000 1281.1Salnsn#define MOVSI 0x2000 1291.1Salnsn#define MOVT 0xf2c00000 1301.1Salnsn#define MOVW 0xf2400000 1311.1Salnsn#define MOV_W 0xea4f0000 1321.1Salnsn#define MOV_WI 0xf04f0000 1331.1Salnsn#define MUL 0xfb00f000 1341.1Salnsn#define MVNS 0x43c0 1351.1Salnsn#define MVN_W 0xea6f0000 1361.1Salnsn#define MVN_WI 0xf06f0000 1371.1Salnsn#define NOP 0xbf00 1381.1Salnsn#define ORNI 0xf0600000 1391.1Salnsn#define ORRI 0xf0400000 1401.1Salnsn#define ORRS 0x4300 1411.1Salnsn#define ORR_W 0xea400000 1421.3Salnsn#define POP 0xbc00 1431.1Salnsn#define POP_W 0xe8bd0000 1441.3Salnsn#define PUSH 0xb400 1451.1Salnsn#define PUSH_W 0xe92d0000 1461.1Salnsn#define RSB_WI 0xf1c00000 1471.1Salnsn#define RSBSI 0x4240 1481.1Salnsn#define SBCI 0xf1600000 1491.1Salnsn#define SBCS 0x4180 1501.1Salnsn#define SBC_W 0xeb600000 1511.1Salnsn#define SMULL 0xfb800000 1521.1Salnsn#define STR_SP 0x9000 1531.1Salnsn#define SUBS 0x1a00 1541.1Salnsn#define SUBSI3 0x1e00 1551.1Salnsn#define SUBSI8 0x3800 1561.1Salnsn#define SUB_W 0xeba00000 1571.1Salnsn#define SUBWI 0xf2a00000 1581.1Salnsn#define SUB_SP 0xb080 1591.1Salnsn#define SUB_WI 0xf1a00000 1601.1Salnsn#define SXTB 0xb240 1611.1Salnsn#define SXTB_W 0xfa4ff080 1621.1Salnsn#define SXTH 0xb200 1631.1Salnsn#define SXTH_W 0xfa0ff080 1641.1Salnsn#define TST 0x4200 1651.1Salnsn#define UMULL 0xfba00000 1661.1Salnsn#define UXTB 0xb2c0 1671.1Salnsn#define UXTB_W 0xfa5ff080 1681.1Salnsn#define UXTH 0xb280 1691.1Salnsn#define UXTH_W 0xfa1ff080 1701.1Salnsn#define VABS_F32 0xeeb00ac0 1711.1Salnsn#define VADD_F32 0xee300a00 1721.1Salnsn#define VCMP_F32 0xeeb40a40 1731.3Salnsn#define VCVT_F32_S32 0xeeb80ac0 1741.3Salnsn#define VCVT_F64_F32 0xeeb70ac0 1751.3Salnsn#define VCVT_S32_F32 0xeebd0ac0 1761.1Salnsn#define VDIV_F32 0xee800a00 1771.1Salnsn#define VMOV_F32 0xeeb00a40 1781.3Salnsn#define VMOV 0xee000a10 1791.1Salnsn#define VMRS 0xeef1fa10 1801.1Salnsn#define VMUL_F32 0xee200a00 1811.1Salnsn#define VNEG_F32 0xeeb10a40 1821.1Salnsn#define VSTR_F32 0xed000a00 1831.1Salnsn#define VSUB_F32 0xee300a40 1841.1Salnsn 1851.3Salnsnstatic sljit_s32 push_inst16(struct sljit_compiler *compiler, sljit_ins inst) 1861.1Salnsn{ 1871.3Salnsn sljit_u16 *ptr; 1881.1Salnsn SLJIT_ASSERT(!(inst & 0xffff0000)); 1891.1Salnsn 1901.3Salnsn ptr = (sljit_u16*)ensure_buf(compiler, sizeof(sljit_u16)); 1911.1Salnsn FAIL_IF(!ptr); 1921.1Salnsn *ptr = inst; 1931.1Salnsn compiler->size++; 1941.1Salnsn return SLJIT_SUCCESS; 1951.1Salnsn} 1961.1Salnsn 1971.3Salnsnstatic sljit_s32 push_inst32(struct sljit_compiler *compiler, sljit_ins inst) 1981.1Salnsn{ 1991.3Salnsn sljit_u16 *ptr = (sljit_u16*)ensure_buf(compiler, sizeof(sljit_ins)); 2001.1Salnsn FAIL_IF(!ptr); 2011.1Salnsn *ptr++ = inst >> 16; 2021.1Salnsn *ptr = inst; 2031.1Salnsn compiler->size += 2; 2041.1Salnsn return SLJIT_SUCCESS; 2051.1Salnsn} 2061.1Salnsn 2071.3Salnsnstatic SLJIT_INLINE sljit_s32 emit_imm32_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm) 2081.1Salnsn{ 2091.1Salnsn FAIL_IF(push_inst32(compiler, MOVW | RD4(dst) | 2101.1Salnsn COPY_BITS(imm, 12, 16, 4) | COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | (imm & 0xff))); 2111.1Salnsn return push_inst32(compiler, MOVT | RD4(dst) | 2121.1Salnsn COPY_BITS(imm, 12 + 16, 16, 4) | COPY_BITS(imm, 11 + 16, 26, 1) | COPY_BITS(imm, 8 + 16, 12, 3) | ((imm & 0xff0000) >> 16)); 2131.1Salnsn} 2141.1Salnsn 2151.3Salnsnstatic SLJIT_INLINE void modify_imm32_const(sljit_u16 *inst, sljit_uw new_imm) 2161.1Salnsn{ 2171.3Salnsn sljit_s32 dst = inst[1] & 0x0f00; 2181.1Salnsn SLJIT_ASSERT(((inst[0] & 0xfbf0) == (MOVW >> 16)) && ((inst[2] & 0xfbf0) == (MOVT >> 16)) && dst == (inst[3] & 0x0f00)); 2191.1Salnsn inst[0] = (MOVW >> 16) | COPY_BITS(new_imm, 12, 0, 4) | COPY_BITS(new_imm, 11, 10, 1); 2201.1Salnsn inst[1] = dst | COPY_BITS(new_imm, 8, 12, 3) | (new_imm & 0xff); 2211.1Salnsn inst[2] = (MOVT >> 16) | COPY_BITS(new_imm, 12 + 16, 0, 4) | COPY_BITS(new_imm, 11 + 16, 10, 1); 2221.1Salnsn inst[3] = dst | COPY_BITS(new_imm, 8 + 16, 12, 3) | ((new_imm & 0xff0000) >> 16); 2231.1Salnsn} 2241.1Salnsn 2251.4Salnsnstatic SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_u16 *code_ptr, sljit_u16 *code, sljit_sw executable_offset) 2261.1Salnsn{ 2271.1Salnsn sljit_sw diff; 2281.1Salnsn 2291.1Salnsn if (jump->flags & SLJIT_REWRITABLE_JUMP) 2301.1Salnsn return 0; 2311.1Salnsn 2321.1Salnsn if (jump->flags & JUMP_ADDR) { 2331.1Salnsn /* Branch to ARM code is not optimized yet. */ 2341.1Salnsn if (!(jump->u.target & 0x1)) 2351.1Salnsn return 0; 2361.4Salnsn diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset) >> 1; 2371.1Salnsn } 2381.1Salnsn else { 2391.1Salnsn SLJIT_ASSERT(jump->flags & JUMP_LABEL); 2401.1Salnsn diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2)) >> 1; 2411.1Salnsn } 2421.1Salnsn 2431.1Salnsn if (jump->flags & IS_COND) { 2441.1Salnsn SLJIT_ASSERT(!(jump->flags & IS_BL)); 2451.1Salnsn if (diff <= 127 && diff >= -128) { 2461.1Salnsn jump->flags |= PATCH_TYPE1; 2471.1Salnsn return 5; 2481.1Salnsn } 2491.1Salnsn if (diff <= 524287 && diff >= -524288) { 2501.1Salnsn jump->flags |= PATCH_TYPE2; 2511.1Salnsn return 4; 2521.1Salnsn } 2531.1Salnsn /* +1 comes from the prefix IT instruction. */ 2541.1Salnsn diff--; 2551.1Salnsn if (diff <= 8388607 && diff >= -8388608) { 2561.1Salnsn jump->flags |= PATCH_TYPE3; 2571.1Salnsn return 3; 2581.1Salnsn } 2591.1Salnsn } 2601.1Salnsn else if (jump->flags & IS_BL) { 2611.1Salnsn if (diff <= 8388607 && diff >= -8388608) { 2621.1Salnsn jump->flags |= PATCH_BL; 2631.1Salnsn return 3; 2641.1Salnsn } 2651.1Salnsn } 2661.1Salnsn else { 2671.1Salnsn if (diff <= 1023 && diff >= -1024) { 2681.1Salnsn jump->flags |= PATCH_TYPE4; 2691.1Salnsn return 4; 2701.1Salnsn } 2711.1Salnsn if (diff <= 8388607 && diff >= -8388608) { 2721.1Salnsn jump->flags |= PATCH_TYPE5; 2731.1Salnsn return 3; 2741.1Salnsn } 2751.1Salnsn } 2761.1Salnsn 2771.1Salnsn return 0; 2781.1Salnsn} 2791.1Salnsn 2801.4Salnsnstatic SLJIT_INLINE void set_jump_instruction(struct sljit_jump *jump, sljit_sw executable_offset) 2811.1Salnsn{ 2821.3Salnsn sljit_s32 type = (jump->flags >> 4) & 0xf; 2831.1Salnsn sljit_sw diff; 2841.3Salnsn sljit_u16 *jump_inst; 2851.3Salnsn sljit_s32 s, j1, j2; 2861.1Salnsn 2871.1Salnsn if (SLJIT_UNLIKELY(type == 0)) { 2881.3Salnsn modify_imm32_const((sljit_u16*)jump->addr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target); 2891.1Salnsn return; 2901.1Salnsn } 2911.1Salnsn 2921.1Salnsn if (jump->flags & JUMP_ADDR) { 2931.1Salnsn SLJIT_ASSERT(jump->u.target & 0x1); 2941.4Salnsn diff = ((sljit_sw)jump->u.target - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1; 2951.4Salnsn } 2961.4Salnsn else { 2971.4Salnsn SLJIT_ASSERT(jump->u.label->addr & 0x1); 2981.4Salnsn diff = ((sljit_sw)(jump->u.label->addr) - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1; 2991.1Salnsn } 3001.3Salnsn jump_inst = (sljit_u16*)jump->addr; 3011.1Salnsn 3021.1Salnsn switch (type) { 3031.1Salnsn case 1: 3041.1Salnsn /* Encoding T1 of 'B' instruction */ 3051.1Salnsn SLJIT_ASSERT(diff <= 127 && diff >= -128 && (jump->flags & IS_COND)); 3061.1Salnsn jump_inst[0] = 0xd000 | (jump->flags & 0xf00) | (diff & 0xff); 3071.1Salnsn return; 3081.1Salnsn case 2: 3091.1Salnsn /* Encoding T3 of 'B' instruction */ 3101.1Salnsn SLJIT_ASSERT(diff <= 524287 && diff >= -524288 && (jump->flags & IS_COND)); 3111.1Salnsn jump_inst[0] = 0xf000 | COPY_BITS(jump->flags, 8, 6, 4) | COPY_BITS(diff, 11, 0, 6) | COPY_BITS(diff, 19, 10, 1); 3121.1Salnsn jump_inst[1] = 0x8000 | COPY_BITS(diff, 17, 13, 1) | COPY_BITS(diff, 18, 11, 1) | (diff & 0x7ff); 3131.1Salnsn return; 3141.1Salnsn case 3: 3151.1Salnsn SLJIT_ASSERT(jump->flags & IS_COND); 3161.1Salnsn *jump_inst++ = IT | ((jump->flags >> 4) & 0xf0) | 0x8; 3171.1Salnsn diff--; 3181.1Salnsn type = 5; 3191.1Salnsn break; 3201.1Salnsn case 4: 3211.1Salnsn /* Encoding T2 of 'B' instruction */ 3221.1Salnsn SLJIT_ASSERT(diff <= 1023 && diff >= -1024 && !(jump->flags & IS_COND)); 3231.1Salnsn jump_inst[0] = 0xe000 | (diff & 0x7ff); 3241.1Salnsn return; 3251.1Salnsn } 3261.1Salnsn 3271.1Salnsn SLJIT_ASSERT(diff <= 8388607 && diff >= -8388608); 3281.1Salnsn 3291.1Salnsn /* Really complex instruction form for branches. */ 3301.1Salnsn s = (diff >> 23) & 0x1; 3311.1Salnsn j1 = (~(diff >> 21) ^ s) & 0x1; 3321.1Salnsn j2 = (~(diff >> 22) ^ s) & 0x1; 3331.1Salnsn jump_inst[0] = 0xf000 | (s << 10) | COPY_BITS(diff, 11, 0, 10); 3341.1Salnsn jump_inst[1] = (j1 << 13) | (j2 << 11) | (diff & 0x7ff); 3351.1Salnsn 3361.1Salnsn /* The others have a common form. */ 3371.1Salnsn if (type == 5) /* Encoding T4 of 'B' instruction */ 3381.1Salnsn jump_inst[1] |= 0x9000; 3391.1Salnsn else if (type == 6) /* Encoding T1 of 'BL' instruction */ 3401.1Salnsn jump_inst[1] |= 0xd000; 3411.1Salnsn else 3421.4Salnsn SLJIT_UNREACHABLE(); 3431.1Salnsn} 3441.1Salnsn 3451.1SalnsnSLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) 3461.1Salnsn{ 3471.1Salnsn struct sljit_memory_fragment *buf; 3481.3Salnsn sljit_u16 *code; 3491.3Salnsn sljit_u16 *code_ptr; 3501.3Salnsn sljit_u16 *buf_ptr; 3511.3Salnsn sljit_u16 *buf_end; 3521.1Salnsn sljit_uw half_count; 3531.4Salnsn sljit_sw executable_offset; 3541.1Salnsn 3551.1Salnsn struct sljit_label *label; 3561.1Salnsn struct sljit_jump *jump; 3571.1Salnsn struct sljit_const *const_; 3581.1Salnsn 3591.1Salnsn CHECK_ERROR_PTR(); 3601.3Salnsn CHECK_PTR(check_sljit_generate_code(compiler)); 3611.1Salnsn reverse_buf(compiler); 3621.1Salnsn 3631.3Salnsn code = (sljit_u16*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_u16)); 3641.1Salnsn PTR_FAIL_WITH_EXEC_IF(code); 3651.1Salnsn buf = compiler->buf; 3661.1Salnsn 3671.1Salnsn code_ptr = code; 3681.1Salnsn half_count = 0; 3691.4Salnsn executable_offset = SLJIT_EXEC_OFFSET(code); 3701.4Salnsn 3711.1Salnsn label = compiler->labels; 3721.1Salnsn jump = compiler->jumps; 3731.1Salnsn const_ = compiler->consts; 3741.1Salnsn 3751.1Salnsn do { 3761.3Salnsn buf_ptr = (sljit_u16*)buf->memory; 3771.1Salnsn buf_end = buf_ptr + (buf->used_size >> 1); 3781.1Salnsn do { 3791.1Salnsn *code_ptr = *buf_ptr++; 3801.1Salnsn /* These structures are ordered by their address. */ 3811.1Salnsn SLJIT_ASSERT(!label || label->size >= half_count); 3821.1Salnsn SLJIT_ASSERT(!jump || jump->addr >= half_count); 3831.1Salnsn SLJIT_ASSERT(!const_ || const_->addr >= half_count); 3841.1Salnsn if (label && label->size == half_count) { 3851.4Salnsn label->addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1; 3861.1Salnsn label->size = code_ptr - code; 3871.1Salnsn label = label->next; 3881.1Salnsn } 3891.1Salnsn if (jump && jump->addr == half_count) { 3901.1Salnsn jump->addr = (sljit_uw)code_ptr - ((jump->flags & IS_COND) ? 10 : 8); 3911.4Salnsn code_ptr -= detect_jump_type(jump, code_ptr, code, executable_offset); 3921.1Salnsn jump = jump->next; 3931.1Salnsn } 3941.1Salnsn if (const_ && const_->addr == half_count) { 3951.1Salnsn const_->addr = (sljit_uw)code_ptr; 3961.1Salnsn const_ = const_->next; 3971.1Salnsn } 3981.1Salnsn code_ptr ++; 3991.1Salnsn half_count ++; 4001.1Salnsn } while (buf_ptr < buf_end); 4011.1Salnsn 4021.1Salnsn buf = buf->next; 4031.1Salnsn } while (buf); 4041.1Salnsn 4051.1Salnsn if (label && label->size == half_count) { 4061.4Salnsn label->addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1; 4071.1Salnsn label->size = code_ptr - code; 4081.1Salnsn label = label->next; 4091.1Salnsn } 4101.1Salnsn 4111.1Salnsn SLJIT_ASSERT(!label); 4121.1Salnsn SLJIT_ASSERT(!jump); 4131.1Salnsn SLJIT_ASSERT(!const_); 4141.1Salnsn SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size); 4151.1Salnsn 4161.1Salnsn jump = compiler->jumps; 4171.1Salnsn while (jump) { 4181.4Salnsn set_jump_instruction(jump, executable_offset); 4191.1Salnsn jump = jump->next; 4201.1Salnsn } 4211.1Salnsn 4221.1Salnsn compiler->error = SLJIT_ERR_COMPILED; 4231.4Salnsn compiler->executable_offset = executable_offset; 4241.3Salnsn compiler->executable_size = (code_ptr - code) * sizeof(sljit_u16); 4251.4Salnsn 4261.4Salnsn code = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset); 4271.4Salnsn code_ptr = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); 4281.4Salnsn 4291.1Salnsn SLJIT_CACHE_FLUSH(code, code_ptr); 4301.1Salnsn /* Set thumb mode flag. */ 4311.1Salnsn return (void*)((sljit_uw)code | 0x1); 4321.1Salnsn} 4331.1Salnsn 4341.1Salnsn/* --------------------------------------------------------------------- */ 4351.1Salnsn/* Core code generator functions. */ 4361.1Salnsn/* --------------------------------------------------------------------- */ 4371.1Salnsn 4381.1Salnsn#define INVALID_IMM 0x80000000 4391.1Salnsnstatic sljit_uw get_imm(sljit_uw imm) 4401.1Salnsn{ 4411.1Salnsn /* Thumb immediate form. */ 4421.3Salnsn sljit_s32 counter; 4431.1Salnsn 4441.1Salnsn if (imm <= 0xff) 4451.1Salnsn return imm; 4461.1Salnsn 4471.1Salnsn if ((imm & 0xffff) == (imm >> 16)) { 4481.1Salnsn /* Some special cases. */ 4491.1Salnsn if (!(imm & 0xff00)) 4501.1Salnsn return (1 << 12) | (imm & 0xff); 4511.1Salnsn if (!(imm & 0xff)) 4521.1Salnsn return (2 << 12) | ((imm >> 8) & 0xff); 4531.1Salnsn if ((imm & 0xff00) == ((imm & 0xff) << 8)) 4541.1Salnsn return (3 << 12) | (imm & 0xff); 4551.1Salnsn } 4561.1Salnsn 4571.1Salnsn /* Assembly optimization: count leading zeroes? */ 4581.1Salnsn counter = 8; 4591.1Salnsn if (!(imm & 0xffff0000)) { 4601.1Salnsn counter += 16; 4611.1Salnsn imm <<= 16; 4621.1Salnsn } 4631.1Salnsn if (!(imm & 0xff000000)) { 4641.1Salnsn counter += 8; 4651.1Salnsn imm <<= 8; 4661.1Salnsn } 4671.1Salnsn if (!(imm & 0xf0000000)) { 4681.1Salnsn counter += 4; 4691.1Salnsn imm <<= 4; 4701.1Salnsn } 4711.1Salnsn if (!(imm & 0xc0000000)) { 4721.1Salnsn counter += 2; 4731.1Salnsn imm <<= 2; 4741.1Salnsn } 4751.1Salnsn if (!(imm & 0x80000000)) { 4761.1Salnsn counter += 1; 4771.1Salnsn imm <<= 1; 4781.1Salnsn } 4791.1Salnsn /* Since imm >= 128, this must be true. */ 4801.1Salnsn SLJIT_ASSERT(counter <= 31); 4811.1Salnsn 4821.1Salnsn if (imm & 0x00ffffff) 4831.1Salnsn return INVALID_IMM; /* Cannot be encoded. */ 4841.1Salnsn 4851.1Salnsn return ((imm >> 24) & 0x7f) | COPY_BITS(counter, 4, 26, 1) | COPY_BITS(counter, 1, 12, 3) | COPY_BITS(counter, 0, 7, 1); 4861.1Salnsn} 4871.1Salnsn 4881.3Salnsnstatic sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm) 4891.1Salnsn{ 4901.1Salnsn sljit_uw tmp; 4911.1Salnsn 4921.1Salnsn if (imm >= 0x10000) { 4931.1Salnsn tmp = get_imm(imm); 4941.1Salnsn if (tmp != INVALID_IMM) 4951.1Salnsn return push_inst32(compiler, MOV_WI | RD4(dst) | tmp); 4961.1Salnsn tmp = get_imm(~imm); 4971.1Salnsn if (tmp != INVALID_IMM) 4981.1Salnsn return push_inst32(compiler, MVN_WI | RD4(dst) | tmp); 4991.1Salnsn } 5001.1Salnsn 5011.1Salnsn /* set low 16 bits, set hi 16 bits to 0. */ 5021.1Salnsn FAIL_IF(push_inst32(compiler, MOVW | RD4(dst) | 5031.1Salnsn COPY_BITS(imm, 12, 16, 4) | COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | (imm & 0xff))); 5041.1Salnsn 5051.1Salnsn /* set hi 16 bit if needed. */ 5061.1Salnsn if (imm >= 0x10000) 5071.1Salnsn return push_inst32(compiler, MOVT | RD4(dst) | 5081.1Salnsn COPY_BITS(imm, 12 + 16, 16, 4) | COPY_BITS(imm, 11 + 16, 26, 1) | COPY_BITS(imm, 8 + 16, 12, 3) | ((imm & 0xff0000) >> 16)); 5091.1Salnsn return SLJIT_SUCCESS; 5101.1Salnsn} 5111.1Salnsn 5121.1Salnsn#define ARG1_IMM 0x0010000 5131.1Salnsn#define ARG2_IMM 0x0020000 5141.1Salnsn/* SET_FLAGS must be 0x100000 as it is also the value of S bit (can be used for optimization). */ 5151.1Salnsn#define SET_FLAGS 0x0100000 5161.1Salnsn#define UNUSED_RETURN 0x0200000 5171.1Salnsn 5181.3Salnsnstatic sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 dst, sljit_uw arg1, sljit_uw arg2) 5191.1Salnsn{ 5201.1Salnsn /* dst must be register, TMP_REG1 5211.4Salnsn arg1 must be register, imm 5221.4Salnsn arg2 must be register, imm */ 5231.3Salnsn sljit_s32 reg; 5241.1Salnsn sljit_uw imm, nimm; 5251.1Salnsn 5261.1Salnsn if (SLJIT_UNLIKELY((flags & (ARG1_IMM | ARG2_IMM)) == (ARG1_IMM | ARG2_IMM))) { 5271.4Salnsn /* Both are immediates, no temporaries are used. */ 5281.1Salnsn flags &= ~ARG1_IMM; 5291.1Salnsn FAIL_IF(load_immediate(compiler, TMP_REG1, arg1)); 5301.1Salnsn arg1 = TMP_REG1; 5311.1Salnsn } 5321.1Salnsn 5331.1Salnsn if (flags & (ARG1_IMM | ARG2_IMM)) { 5341.1Salnsn reg = (flags & ARG2_IMM) ? arg1 : arg2; 5351.1Salnsn imm = (flags & ARG2_IMM) ? arg2 : arg1; 5361.1Salnsn 5371.1Salnsn switch (flags & 0xffff) { 5381.1Salnsn case SLJIT_CLZ: 5391.1Salnsn case SLJIT_MUL: 5401.1Salnsn /* No form with immediate operand. */ 5411.1Salnsn break; 5421.1Salnsn case SLJIT_MOV: 5431.4Salnsn SLJIT_ASSERT(!(flags & SET_FLAGS) && (flags & ARG2_IMM) && arg1 == TMP_REG2); 5441.1Salnsn return load_immediate(compiler, dst, imm); 5451.1Salnsn case SLJIT_NOT: 5461.1Salnsn if (!(flags & SET_FLAGS)) 5471.1Salnsn return load_immediate(compiler, dst, ~imm); 5481.1Salnsn /* Since the flags should be set, we just fallback to the register mode. 5491.1Salnsn Although some clever things could be done here, "NOT IMM" does not worth the efforts. */ 5501.1Salnsn break; 5511.1Salnsn case SLJIT_ADD: 5521.1Salnsn nimm = -imm; 5531.4Salnsn if (IS_2_LO_REGS(reg, dst)) { 5541.1Salnsn if (imm <= 0x7) 5551.1Salnsn return push_inst16(compiler, ADDSI3 | IMM3(imm) | RD3(dst) | RN3(reg)); 5561.1Salnsn if (nimm <= 0x7) 5571.1Salnsn return push_inst16(compiler, SUBSI3 | IMM3(nimm) | RD3(dst) | RN3(reg)); 5581.1Salnsn if (reg == dst) { 5591.1Salnsn if (imm <= 0xff) 5601.1Salnsn return push_inst16(compiler, ADDSI8 | IMM8(imm) | RDN3(dst)); 5611.1Salnsn if (nimm <= 0xff) 5621.1Salnsn return push_inst16(compiler, SUBSI8 | IMM8(nimm) | RDN3(dst)); 5631.1Salnsn } 5641.1Salnsn } 5651.1Salnsn if (!(flags & SET_FLAGS)) { 5661.1Salnsn if (imm <= 0xfff) 5671.1Salnsn return push_inst32(compiler, ADDWI | RD4(dst) | RN4(reg) | IMM12(imm)); 5681.1Salnsn if (nimm <= 0xfff) 5691.1Salnsn return push_inst32(compiler, SUBWI | RD4(dst) | RN4(reg) | IMM12(nimm)); 5701.1Salnsn } 5711.1Salnsn imm = get_imm(imm); 5721.1Salnsn if (imm != INVALID_IMM) 5731.1Salnsn return push_inst32(compiler, ADD_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); 5741.1Salnsn break; 5751.1Salnsn case SLJIT_ADDC: 5761.1Salnsn imm = get_imm(imm); 5771.1Salnsn if (imm != INVALID_IMM) 5781.1Salnsn return push_inst32(compiler, ADCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); 5791.1Salnsn break; 5801.1Salnsn case SLJIT_SUB: 5811.1Salnsn if (flags & ARG1_IMM) { 5821.4Salnsn if (imm == 0 && IS_2_LO_REGS(reg, dst)) 5831.1Salnsn return push_inst16(compiler, RSBSI | RD3(dst) | RN3(reg)); 5841.1Salnsn imm = get_imm(imm); 5851.1Salnsn if (imm != INVALID_IMM) 5861.1Salnsn return push_inst32(compiler, RSB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); 5871.1Salnsn break; 5881.1Salnsn } 5891.1Salnsn nimm = -imm; 5901.4Salnsn if (IS_2_LO_REGS(reg, dst)) { 5911.1Salnsn if (imm <= 0x7) 5921.1Salnsn return push_inst16(compiler, SUBSI3 | IMM3(imm) | RD3(dst) | RN3(reg)); 5931.1Salnsn if (nimm <= 0x7) 5941.1Salnsn return push_inst16(compiler, ADDSI3 | IMM3(nimm) | RD3(dst) | RN3(reg)); 5951.1Salnsn if (reg == dst) { 5961.1Salnsn if (imm <= 0xff) 5971.1Salnsn return push_inst16(compiler, SUBSI8 | IMM8(imm) | RDN3(dst)); 5981.1Salnsn if (nimm <= 0xff) 5991.1Salnsn return push_inst16(compiler, ADDSI8 | IMM8(nimm) | RDN3(dst)); 6001.1Salnsn } 6011.1Salnsn if (imm <= 0xff && (flags & UNUSED_RETURN)) 6021.1Salnsn return push_inst16(compiler, CMPI | IMM8(imm) | RDN3(reg)); 6031.1Salnsn } 6041.1Salnsn if (!(flags & SET_FLAGS)) { 6051.1Salnsn if (imm <= 0xfff) 6061.1Salnsn return push_inst32(compiler, SUBWI | RD4(dst) | RN4(reg) | IMM12(imm)); 6071.1Salnsn if (nimm <= 0xfff) 6081.1Salnsn return push_inst32(compiler, ADDWI | RD4(dst) | RN4(reg) | IMM12(nimm)); 6091.1Salnsn } 6101.1Salnsn imm = get_imm(imm); 6111.1Salnsn if (imm != INVALID_IMM) 6121.1Salnsn return push_inst32(compiler, SUB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); 6131.1Salnsn break; 6141.1Salnsn case SLJIT_SUBC: 6151.1Salnsn if (flags & ARG1_IMM) 6161.1Salnsn break; 6171.1Salnsn imm = get_imm(imm); 6181.1Salnsn if (imm != INVALID_IMM) 6191.1Salnsn return push_inst32(compiler, SBCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); 6201.1Salnsn break; 6211.1Salnsn case SLJIT_AND: 6221.1Salnsn nimm = get_imm(imm); 6231.1Salnsn if (nimm != INVALID_IMM) 6241.1Salnsn return push_inst32(compiler, ANDI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm); 6251.1Salnsn imm = get_imm(imm); 6261.1Salnsn if (imm != INVALID_IMM) 6271.1Salnsn return push_inst32(compiler, BICI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); 6281.1Salnsn break; 6291.1Salnsn case SLJIT_OR: 6301.1Salnsn nimm = get_imm(imm); 6311.1Salnsn if (nimm != INVALID_IMM) 6321.1Salnsn return push_inst32(compiler, ORRI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm); 6331.1Salnsn imm = get_imm(imm); 6341.1Salnsn if (imm != INVALID_IMM) 6351.1Salnsn return push_inst32(compiler, ORNI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); 6361.1Salnsn break; 6371.1Salnsn case SLJIT_XOR: 6381.1Salnsn imm = get_imm(imm); 6391.1Salnsn if (imm != INVALID_IMM) 6401.1Salnsn return push_inst32(compiler, EORI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); 6411.1Salnsn break; 6421.1Salnsn case SLJIT_SHL: 6431.1Salnsn case SLJIT_LSHR: 6441.1Salnsn case SLJIT_ASHR: 6451.1Salnsn if (flags & ARG1_IMM) 6461.1Salnsn break; 6471.1Salnsn imm &= 0x1f; 6481.1Salnsn if (imm == 0) { 6491.1Salnsn if (!(flags & SET_FLAGS)) 6501.1Salnsn return push_inst16(compiler, MOV | SET_REGS44(dst, reg)); 6511.1Salnsn if (IS_2_LO_REGS(dst, reg)) 6521.1Salnsn return push_inst16(compiler, MOVS | RD3(dst) | RN3(reg)); 6531.1Salnsn return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(dst) | RM4(reg)); 6541.1Salnsn } 6551.1Salnsn switch (flags & 0xffff) { 6561.1Salnsn case SLJIT_SHL: 6571.4Salnsn if (IS_2_LO_REGS(dst, reg)) 6581.1Salnsn return push_inst16(compiler, LSLSI | RD3(dst) | RN3(reg) | (imm << 6)); 6591.1Salnsn return push_inst32(compiler, LSL_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); 6601.1Salnsn case SLJIT_LSHR: 6611.4Salnsn if (IS_2_LO_REGS(dst, reg)) 6621.1Salnsn return push_inst16(compiler, LSRSI | RD3(dst) | RN3(reg) | (imm << 6)); 6631.1Salnsn return push_inst32(compiler, LSR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); 6641.1Salnsn default: /* SLJIT_ASHR */ 6651.4Salnsn if (IS_2_LO_REGS(dst, reg)) 6661.1Salnsn return push_inst16(compiler, ASRSI | RD3(dst) | RN3(reg) | (imm << 6)); 6671.1Salnsn return push_inst32(compiler, ASR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); 6681.1Salnsn } 6691.1Salnsn default: 6701.4Salnsn SLJIT_UNREACHABLE(); 6711.1Salnsn break; 6721.1Salnsn } 6731.1Salnsn 6741.1Salnsn if (flags & ARG2_IMM) { 6751.4Salnsn imm = arg2; 6761.4Salnsn arg2 = (arg1 == TMP_REG1) ? TMP_REG2 : TMP_REG1; 6771.4Salnsn FAIL_IF(load_immediate(compiler, arg2, imm)); 6781.1Salnsn } 6791.1Salnsn else { 6801.4Salnsn imm = arg1; 6811.4Salnsn arg1 = (arg2 == TMP_REG1) ? TMP_REG2 : TMP_REG1; 6821.4Salnsn FAIL_IF(load_immediate(compiler, arg1, imm)); 6831.1Salnsn } 6841.4Salnsn 6851.4Salnsn SLJIT_ASSERT(arg1 != arg2); 6861.1Salnsn } 6871.1Salnsn 6881.1Salnsn /* Both arguments are registers. */ 6891.1Salnsn switch (flags & 0xffff) { 6901.1Salnsn case SLJIT_MOV: 6911.3Salnsn case SLJIT_MOV_U32: 6921.3Salnsn case SLJIT_MOV_S32: 6931.1Salnsn case SLJIT_MOV_P: 6941.1Salnsn case SLJIT_MOVU: 6951.3Salnsn case SLJIT_MOVU_U32: 6961.3Salnsn case SLJIT_MOVU_S32: 6971.1Salnsn case SLJIT_MOVU_P: 6981.4Salnsn SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2); 6991.1Salnsn if (dst == arg2) 7001.1Salnsn return SLJIT_SUCCESS; 7011.1Salnsn return push_inst16(compiler, MOV | SET_REGS44(dst, arg2)); 7021.3Salnsn case SLJIT_MOV_U8: 7031.3Salnsn case SLJIT_MOVU_U8: 7041.4Salnsn SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2); 7051.1Salnsn if (IS_2_LO_REGS(dst, arg2)) 7061.1Salnsn return push_inst16(compiler, UXTB | RD3(dst) | RN3(arg2)); 7071.1Salnsn return push_inst32(compiler, UXTB_W | RD4(dst) | RM4(arg2)); 7081.3Salnsn case SLJIT_MOV_S8: 7091.3Salnsn case SLJIT_MOVU_S8: 7101.4Salnsn SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2); 7111.1Salnsn if (IS_2_LO_REGS(dst, arg2)) 7121.1Salnsn return push_inst16(compiler, SXTB | RD3(dst) | RN3(arg2)); 7131.1Salnsn return push_inst32(compiler, SXTB_W | RD4(dst) | RM4(arg2)); 7141.3Salnsn case SLJIT_MOV_U16: 7151.3Salnsn case SLJIT_MOVU_U16: 7161.4Salnsn SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2); 7171.1Salnsn if (IS_2_LO_REGS(dst, arg2)) 7181.1Salnsn return push_inst16(compiler, UXTH | RD3(dst) | RN3(arg2)); 7191.1Salnsn return push_inst32(compiler, UXTH_W | RD4(dst) | RM4(arg2)); 7201.3Salnsn case SLJIT_MOV_S16: 7211.3Salnsn case SLJIT_MOVU_S16: 7221.4Salnsn SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2); 7231.1Salnsn if (IS_2_LO_REGS(dst, arg2)) 7241.1Salnsn return push_inst16(compiler, SXTH | RD3(dst) | RN3(arg2)); 7251.1Salnsn return push_inst32(compiler, SXTH_W | RD4(dst) | RM4(arg2)); 7261.1Salnsn case SLJIT_NOT: 7271.4Salnsn SLJIT_ASSERT(arg1 == TMP_REG2); 7281.4Salnsn if (IS_2_LO_REGS(dst, arg2)) 7291.1Salnsn return push_inst16(compiler, MVNS | RD3(dst) | RN3(arg2)); 7301.1Salnsn return push_inst32(compiler, MVN_W | (flags & SET_FLAGS) | RD4(dst) | RM4(arg2)); 7311.1Salnsn case SLJIT_CLZ: 7321.4Salnsn SLJIT_ASSERT(arg1 == TMP_REG2); 7331.1Salnsn FAIL_IF(push_inst32(compiler, CLZ | RN4(arg2) | RD4(dst) | RM4(arg2))); 7341.1Salnsn if (flags & SET_FLAGS) { 7351.1Salnsn if (reg_map[dst] <= 7) 7361.1Salnsn return push_inst16(compiler, CMPI | RDN3(dst)); 7371.1Salnsn return push_inst32(compiler, ADD_WI | SET_FLAGS | RN4(dst) | RD4(dst)); 7381.1Salnsn } 7391.1Salnsn return SLJIT_SUCCESS; 7401.1Salnsn case SLJIT_ADD: 7411.4Salnsn if (IS_3_LO_REGS(dst, arg1, arg2)) 7421.1Salnsn return push_inst16(compiler, ADDS | RD3(dst) | RN3(arg1) | RM3(arg2)); 7431.1Salnsn if (dst == arg1 && !(flags & SET_FLAGS)) 7441.1Salnsn return push_inst16(compiler, ADD | SET_REGS44(dst, arg2)); 7451.1Salnsn return push_inst32(compiler, ADD_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); 7461.1Salnsn case SLJIT_ADDC: 7471.4Salnsn if (dst == arg1 && IS_2_LO_REGS(dst, arg2)) 7481.1Salnsn return push_inst16(compiler, ADCS | RD3(dst) | RN3(arg2)); 7491.1Salnsn return push_inst32(compiler, ADC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); 7501.1Salnsn case SLJIT_SUB: 7511.4Salnsn if (IS_3_LO_REGS(dst, arg1, arg2)) 7521.1Salnsn return push_inst16(compiler, SUBS | RD3(dst) | RN3(arg1) | RM3(arg2)); 7531.1Salnsn return push_inst32(compiler, SUB_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); 7541.1Salnsn case SLJIT_SUBC: 7551.4Salnsn if (dst == arg1 && IS_2_LO_REGS(dst, arg2)) 7561.1Salnsn return push_inst16(compiler, SBCS | RD3(dst) | RN3(arg2)); 7571.1Salnsn return push_inst32(compiler, SBC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); 7581.1Salnsn case SLJIT_MUL: 7591.1Salnsn if (!(flags & SET_FLAGS)) 7601.1Salnsn return push_inst32(compiler, MUL | RD4(dst) | RN4(arg1) | RM4(arg2)); 7611.4Salnsn SLJIT_ASSERT(dst != TMP_REG2); 7621.1Salnsn FAIL_IF(push_inst32(compiler, SMULL | RT4(dst) | RD4(TMP_REG2) | RN4(arg1) | RM4(arg2))); 7631.1Salnsn /* cmp TMP_REG2, dst asr #31. */ 7641.1Salnsn return push_inst32(compiler, CMP_W | RN4(TMP_REG2) | 0x70e0 | RM4(dst)); 7651.1Salnsn case SLJIT_AND: 7661.4Salnsn if (dst == arg1 && IS_2_LO_REGS(dst, arg2)) 7671.4Salnsn return push_inst16(compiler, ANDS | RD3(dst) | RN3(arg2)); 7681.4Salnsn if ((flags & UNUSED_RETURN) && IS_2_LO_REGS(arg1, arg2)) 7691.4Salnsn return push_inst16(compiler, TST | RD3(arg1) | RN3(arg2)); 7701.1Salnsn return push_inst32(compiler, AND_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); 7711.1Salnsn case SLJIT_OR: 7721.4Salnsn if (dst == arg1 && IS_2_LO_REGS(dst, arg2)) 7731.1Salnsn return push_inst16(compiler, ORRS | RD3(dst) | RN3(arg2)); 7741.1Salnsn return push_inst32(compiler, ORR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); 7751.1Salnsn case SLJIT_XOR: 7761.4Salnsn if (dst == arg1 && IS_2_LO_REGS(dst, arg2)) 7771.1Salnsn return push_inst16(compiler, EORS | RD3(dst) | RN3(arg2)); 7781.1Salnsn return push_inst32(compiler, EOR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); 7791.1Salnsn case SLJIT_SHL: 7801.4Salnsn if (dst == arg1 && IS_2_LO_REGS(dst, arg2)) 7811.1Salnsn return push_inst16(compiler, LSLS | RD3(dst) | RN3(arg2)); 7821.1Salnsn return push_inst32(compiler, LSL_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); 7831.1Salnsn case SLJIT_LSHR: 7841.4Salnsn if (dst == arg1 && IS_2_LO_REGS(dst, arg2)) 7851.1Salnsn return push_inst16(compiler, LSRS | RD3(dst) | RN3(arg2)); 7861.1Salnsn return push_inst32(compiler, LSR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); 7871.1Salnsn case SLJIT_ASHR: 7881.4Salnsn if (dst == arg1 && IS_2_LO_REGS(dst, arg2)) 7891.1Salnsn return push_inst16(compiler, ASRS | RD3(dst) | RN3(arg2)); 7901.1Salnsn return push_inst32(compiler, ASR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); 7911.1Salnsn } 7921.1Salnsn 7931.4Salnsn SLJIT_UNREACHABLE(); 7941.1Salnsn return SLJIT_SUCCESS; 7951.1Salnsn} 7961.1Salnsn 7971.1Salnsn#define STORE 0x01 7981.1Salnsn#define SIGNED 0x02 7991.1Salnsn 8001.1Salnsn#define WORD_SIZE 0x00 8011.1Salnsn#define BYTE_SIZE 0x04 8021.1Salnsn#define HALF_SIZE 0x08 8031.1Salnsn 8041.1Salnsn#define UPDATE 0x10 8051.1Salnsn 8061.1Salnsn#define IS_WORD_SIZE(flags) (!(flags & (BYTE_SIZE | HALF_SIZE))) 8071.1Salnsn#define OFFSET_CHECK(imm, shift) (!(argw & ~(imm << shift))) 8081.1Salnsn 8091.1Salnsn/* 8101.1Salnsn 1st letter: 8111.1Salnsn w = word 8121.1Salnsn b = byte 8131.1Salnsn h = half 8141.1Salnsn 8151.1Salnsn 2nd letter: 8161.1Salnsn s = signed 8171.1Salnsn u = unsigned 8181.1Salnsn 8191.1Salnsn 3rd letter: 8201.1Salnsn l = load 8211.1Salnsn s = store 8221.1Salnsn*/ 8231.1Salnsn 8241.3Salnsnstatic const sljit_ins sljit_mem16[12] = { 8251.1Salnsn/* w u l */ 0x5800 /* ldr */, 8261.1Salnsn/* w u s */ 0x5000 /* str */, 8271.1Salnsn/* w s l */ 0x5800 /* ldr */, 8281.1Salnsn/* w s s */ 0x5000 /* str */, 8291.1Salnsn 8301.1Salnsn/* b u l */ 0x5c00 /* ldrb */, 8311.1Salnsn/* b u s */ 0x5400 /* strb */, 8321.1Salnsn/* b s l */ 0x5600 /* ldrsb */, 8331.1Salnsn/* b s s */ 0x5400 /* strb */, 8341.1Salnsn 8351.1Salnsn/* h u l */ 0x5a00 /* ldrh */, 8361.1Salnsn/* h u s */ 0x5200 /* strh */, 8371.1Salnsn/* h s l */ 0x5e00 /* ldrsh */, 8381.1Salnsn/* h s s */ 0x5200 /* strh */, 8391.1Salnsn}; 8401.1Salnsn 8411.3Salnsnstatic const sljit_ins sljit_mem16_imm5[12] = { 8421.1Salnsn/* w u l */ 0x6800 /* ldr imm5 */, 8431.1Salnsn/* w u s */ 0x6000 /* str imm5 */, 8441.1Salnsn/* w s l */ 0x6800 /* ldr imm5 */, 8451.1Salnsn/* w s s */ 0x6000 /* str imm5 */, 8461.1Salnsn 8471.1Salnsn/* b u l */ 0x7800 /* ldrb imm5 */, 8481.1Salnsn/* b u s */ 0x7000 /* strb imm5 */, 8491.1Salnsn/* b s l */ 0x0000 /* not allowed */, 8501.1Salnsn/* b s s */ 0x7000 /* strb imm5 */, 8511.1Salnsn 8521.1Salnsn/* h u l */ 0x8800 /* ldrh imm5 */, 8531.1Salnsn/* h u s */ 0x8000 /* strh imm5 */, 8541.1Salnsn/* h s l */ 0x0000 /* not allowed */, 8551.1Salnsn/* h s s */ 0x8000 /* strh imm5 */, 8561.1Salnsn}; 8571.1Salnsn 8581.1Salnsn#define MEM_IMM8 0xc00 8591.1Salnsn#define MEM_IMM12 0x800000 8601.3Salnsnstatic const sljit_ins sljit_mem32[12] = { 8611.1Salnsn/* w u l */ 0xf8500000 /* ldr.w */, 8621.1Salnsn/* w u s */ 0xf8400000 /* str.w */, 8631.1Salnsn/* w s l */ 0xf8500000 /* ldr.w */, 8641.1Salnsn/* w s s */ 0xf8400000 /* str.w */, 8651.1Salnsn 8661.1Salnsn/* b u l */ 0xf8100000 /* ldrb.w */, 8671.1Salnsn/* b u s */ 0xf8000000 /* strb.w */, 8681.1Salnsn/* b s l */ 0xf9100000 /* ldrsb.w */, 8691.1Salnsn/* b s s */ 0xf8000000 /* strb.w */, 8701.1Salnsn 8711.1Salnsn/* h u l */ 0xf8300000 /* ldrh.w */, 8721.1Salnsn/* h u s */ 0xf8200000 /* strsh.w */, 8731.1Salnsn/* h s l */ 0xf9300000 /* ldrsh.w */, 8741.1Salnsn/* h s s */ 0xf8200000 /* strsh.w */, 8751.1Salnsn}; 8761.1Salnsn 8771.1Salnsn/* Helper function. Dst should be reg + value, using at most 1 instruction, flags does not set. */ 8781.3Salnsnstatic sljit_s32 emit_set_delta(struct sljit_compiler *compiler, sljit_s32 dst, sljit_s32 reg, sljit_sw value) 8791.1Salnsn{ 8801.1Salnsn if (value >= 0) { 8811.1Salnsn if (value <= 0xfff) 8821.1Salnsn return push_inst32(compiler, ADDWI | RD4(dst) | RN4(reg) | IMM12(value)); 8831.1Salnsn value = get_imm(value); 8841.1Salnsn if (value != INVALID_IMM) 8851.1Salnsn return push_inst32(compiler, ADD_WI | RD4(dst) | RN4(reg) | value); 8861.1Salnsn } 8871.1Salnsn else { 8881.1Salnsn value = -value; 8891.1Salnsn if (value <= 0xfff) 8901.1Salnsn return push_inst32(compiler, SUBWI | RD4(dst) | RN4(reg) | IMM12(value)); 8911.1Salnsn value = get_imm(value); 8921.1Salnsn if (value != INVALID_IMM) 8931.1Salnsn return push_inst32(compiler, SUB_WI | RD4(dst) | RN4(reg) | value); 8941.1Salnsn } 8951.1Salnsn return SLJIT_ERR_UNSUPPORTED; 8961.1Salnsn} 8971.1Salnsn 8981.4Salnsnstatic SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, 8991.4Salnsn sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg) 9001.1Salnsn{ 9011.4Salnsn sljit_s32 other_r; 9021.4Salnsn sljit_s32 update = flags & UPDATE; 9031.4Salnsn sljit_uw tmp; 9041.1Salnsn 9051.1Salnsn SLJIT_ASSERT(arg & SLJIT_MEM); 9061.4Salnsn SLJIT_ASSERT((arg & REG_MASK) != tmp_reg); 9071.4Salnsn flags &= ~UPDATE; 9081.4Salnsn arg &= ~SLJIT_MEM; 9091.1Salnsn 9101.4Salnsn if (SLJIT_UNLIKELY(!(arg & REG_MASK))) { 9111.4Salnsn FAIL_IF(load_immediate(compiler, tmp_reg, argw)); 9121.4Salnsn if (IS_2_LO_REGS(reg, tmp_reg) && sljit_mem16_imm5[flags]) 9131.4Salnsn return push_inst16(compiler, sljit_mem16_imm5[flags] | RD3(reg) | RN3(tmp_reg)); 9141.4Salnsn return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(tmp_reg)); 9151.4Salnsn } 9161.4Salnsn 9171.4Salnsn if (SLJIT_UNLIKELY(update)) { 9181.4Salnsn SLJIT_ASSERT(reg != arg); 9191.1Salnsn 9201.4Salnsn if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { 9211.4Salnsn other_r = OFFS_REG(arg); 9221.1Salnsn arg &= 0xf; 9231.4Salnsn 9241.4Salnsn if (IS_3_LO_REGS(reg, arg, other_r)) 9251.4Salnsn FAIL_IF(push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(other_r))); 9261.4Salnsn else 9271.4Salnsn FAIL_IF(push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(other_r))); 9281.4Salnsn return push_inst16(compiler, ADD | SET_REGS44(arg, other_r)); 9291.4Salnsn } 9301.4Salnsn 9311.4Salnsn if (argw > 0xff) { 9321.4Salnsn tmp = get_imm(argw & ~0xff); 9331.4Salnsn if (tmp != INVALID_IMM) { 9341.4Salnsn push_inst32(compiler, ADD_WI | RD4(arg) | RN4(arg) | tmp); 9351.4Salnsn argw = argw & 0xff; 9361.4Salnsn } 9371.4Salnsn } 9381.4Salnsn else if (argw < -0xff) { 9391.4Salnsn tmp = get_imm(-argw & ~0xff); 9401.4Salnsn if (tmp != INVALID_IMM) { 9411.4Salnsn push_inst32(compiler, SUB_WI | RD4(arg) | RN4(arg) | tmp); 9421.4Salnsn argw = -(-argw & 0xff); 9431.4Salnsn } 9441.4Salnsn } 9451.4Salnsn 9461.4Salnsn if (argw == 0) { 9471.4Salnsn if (IS_2_LO_REGS(reg, arg) && sljit_mem16_imm5[flags]) 9481.4Salnsn return push_inst16(compiler, sljit_mem16_imm5[flags] | RD3(reg) | RN3(arg)); 9491.4Salnsn return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(arg)); 9501.4Salnsn } 9511.4Salnsn 9521.4Salnsn if (argw <= 0xff && argw >= -0xff) { 9531.1Salnsn if (argw >= 0) 9541.1Salnsn argw |= 0x200; 9551.1Salnsn else { 9561.1Salnsn argw = -argw; 9571.1Salnsn } 9581.1Salnsn 9591.1Salnsn SLJIT_ASSERT(argw >= 0 && (argw & 0xff) <= 0xff); 9601.4Salnsn return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM8 | RT4(reg) | RN4(arg) | 0x100 | argw); 9611.1Salnsn } 9621.4Salnsn 9631.4Salnsn FAIL_IF(load_immediate(compiler, tmp_reg, argw)); 9641.4Salnsn 9651.4Salnsn SLJIT_ASSERT(reg != tmp_reg); 9661.4Salnsn 9671.4Salnsn if (IS_3_LO_REGS(reg, arg, tmp_reg)) 9681.4Salnsn FAIL_IF(push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(tmp_reg))); 9691.4Salnsn else 9701.4Salnsn FAIL_IF(push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(tmp_reg))); 9711.4Salnsn return push_inst16(compiler, ADD | SET_REGS44(arg, tmp_reg)); 9721.1Salnsn } 9731.1Salnsn 9741.1Salnsn if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { 9751.1Salnsn argw &= 0x3; 9761.1Salnsn other_r = OFFS_REG(arg); 9771.1Salnsn arg &= 0xf; 9781.1Salnsn 9791.1Salnsn if (!argw && IS_3_LO_REGS(reg, arg, other_r)) 9801.4Salnsn return push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(other_r)); 9811.4Salnsn return push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(other_r) | (argw << 4)); 9821.1Salnsn } 9831.1Salnsn 9841.4Salnsn if (argw > 0xfff) { 9851.4Salnsn tmp = get_imm(argw & ~0xfff); 9861.4Salnsn if (tmp != INVALID_IMM) { 9871.4Salnsn push_inst32(compiler, ADD_WI | RD4(tmp_reg) | RN4(arg) | tmp); 9881.4Salnsn arg = tmp_reg; 9891.4Salnsn argw = argw & 0xfff; 9901.4Salnsn } 9911.4Salnsn } 9921.4Salnsn else if (argw < -0xff) { 9931.4Salnsn tmp = get_imm(-argw & ~0xff); 9941.4Salnsn if (tmp != INVALID_IMM) { 9951.4Salnsn push_inst32(compiler, SUB_WI | RD4(tmp_reg) | RN4(arg) | tmp); 9961.4Salnsn arg = tmp_reg; 9971.4Salnsn argw = -(-argw & 0xff); 9981.4Salnsn } 9991.4Salnsn } 10001.1Salnsn 10011.1Salnsn if (IS_2_LO_REGS(reg, arg) && sljit_mem16_imm5[flags]) { 10021.4Salnsn tmp = 3; 10031.1Salnsn if (IS_WORD_SIZE(flags)) { 10041.1Salnsn if (OFFSET_CHECK(0x1f, 2)) 10051.4Salnsn tmp = 2; 10061.1Salnsn } 10071.1Salnsn else if (flags & BYTE_SIZE) 10081.1Salnsn { 10091.1Salnsn if (OFFSET_CHECK(0x1f, 0)) 10101.4Salnsn tmp = 0; 10111.1Salnsn } 10121.1Salnsn else { 10131.1Salnsn SLJIT_ASSERT(flags & HALF_SIZE); 10141.1Salnsn if (OFFSET_CHECK(0x1f, 1)) 10151.4Salnsn tmp = 1; 10161.1Salnsn } 10171.1Salnsn 10181.4Salnsn if (tmp < 3) 10191.4Salnsn return push_inst16(compiler, sljit_mem16_imm5[flags] | RD3(reg) | RN3(arg) | (argw << (6 - tmp))); 10201.1Salnsn } 10211.4Salnsn else if (SLJIT_UNLIKELY(arg == SLJIT_SP) && IS_WORD_SIZE(flags) && OFFSET_CHECK(0xff, 2) && reg_map[reg] <= 7) { 10221.4Salnsn /* SP based immediate. */ 10231.4Salnsn return push_inst16(compiler, STR_SP | ((flags & STORE) ? 0 : 0x800) | RDN3(reg) | (argw >> 2)); 10241.1Salnsn } 10251.1Salnsn 10261.4Salnsn if (argw >= 0 && argw <= 0xfff) 10271.4Salnsn return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(arg) | argw); 10281.4Salnsn else if (argw < 0 && argw >= -0xff) 10291.4Salnsn return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM8 | RT4(reg) | RN4(arg) | -argw); 10301.1Salnsn 10311.4Salnsn SLJIT_ASSERT(arg != tmp_reg); 10321.1Salnsn 10331.4Salnsn FAIL_IF(load_immediate(compiler, tmp_reg, argw)); 10341.4Salnsn if (IS_3_LO_REGS(reg, arg, tmp_reg)) 10351.4Salnsn return push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(tmp_reg)); 10361.4Salnsn return push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(tmp_reg)); 10371.1Salnsn} 10381.1Salnsn 10391.1Salnsn/* --------------------------------------------------------------------- */ 10401.1Salnsn/* Entry, exit */ 10411.1Salnsn/* --------------------------------------------------------------------- */ 10421.1Salnsn 10431.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler, 10441.3Salnsn sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds, 10451.3Salnsn sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) 10461.1Salnsn{ 10471.3Salnsn sljit_s32 size, i, tmp; 10481.4Salnsn sljit_ins push = 0; 10491.1Salnsn 10501.1Salnsn CHECK_ERROR(); 10511.3Salnsn CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size)); 10521.3Salnsn set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size); 10531.1Salnsn 10541.3Salnsn tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG; 10551.3Salnsn for (i = SLJIT_S0; i >= tmp; i--) 10561.3Salnsn push |= 1 << reg_map[i]; 10571.3Salnsn 10581.3Salnsn for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) 10591.3Salnsn push |= 1 << reg_map[i]; 10601.1Salnsn 10611.3Salnsn FAIL_IF((push & 0xff00) 10621.1Salnsn ? push_inst32(compiler, PUSH_W | (1 << 14) | push) 10631.3Salnsn : push_inst16(compiler, PUSH | (1 << 8) | push)); 10641.1Salnsn 10651.3Salnsn /* Stack must be aligned to 8 bytes: (LR, R4) */ 10661.4Salnsn size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1); 10671.3Salnsn local_size = ((size + local_size + 7) & ~7) - size; 10681.1Salnsn compiler->local_size = local_size; 10691.1Salnsn if (local_size > 0) { 10701.1Salnsn if (local_size <= (127 << 2)) 10711.1Salnsn FAIL_IF(push_inst16(compiler, SUB_SP | (local_size >> 2))); 10721.1Salnsn else 10731.3Salnsn FAIL_IF(emit_op_imm(compiler, SLJIT_SUB | ARG2_IMM, SLJIT_SP, SLJIT_SP, local_size)); 10741.1Salnsn } 10751.1Salnsn 10761.1Salnsn if (args >= 1) 10771.3Salnsn FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_S0, SLJIT_R0))); 10781.1Salnsn if (args >= 2) 10791.3Salnsn FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_S1, SLJIT_R1))); 10801.1Salnsn if (args >= 3) 10811.3Salnsn FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_S2, SLJIT_R2))); 10821.1Salnsn 10831.1Salnsn return SLJIT_SUCCESS; 10841.1Salnsn} 10851.1Salnsn 10861.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler, 10871.3Salnsn sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds, 10881.3Salnsn sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) 10891.1Salnsn{ 10901.3Salnsn sljit_s32 size; 10911.1Salnsn 10921.3Salnsn CHECK_ERROR(); 10931.3Salnsn CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size)); 10941.3Salnsn set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size); 10951.1Salnsn 10961.4Salnsn size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1); 10971.3Salnsn compiler->local_size = ((size + local_size + 7) & ~7) - size; 10981.3Salnsn return SLJIT_SUCCESS; 10991.1Salnsn} 11001.1Salnsn 11011.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw) 11021.1Salnsn{ 11031.3Salnsn sljit_s32 i, tmp; 11041.4Salnsn sljit_ins pop = 0; 11051.1Salnsn 11061.1Salnsn CHECK_ERROR(); 11071.3Salnsn CHECK(check_sljit_emit_return(compiler, op, src, srcw)); 11081.1Salnsn 11091.1Salnsn FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); 11101.1Salnsn 11111.1Salnsn if (compiler->local_size > 0) { 11121.1Salnsn if (compiler->local_size <= (127 << 2)) 11131.1Salnsn FAIL_IF(push_inst16(compiler, ADD_SP | (compiler->local_size >> 2))); 11141.1Salnsn else 11151.3Salnsn FAIL_IF(emit_op_imm(compiler, SLJIT_ADD | ARG2_IMM, SLJIT_SP, SLJIT_SP, compiler->local_size)); 11161.1Salnsn } 11171.1Salnsn 11181.3Salnsn tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG; 11191.3Salnsn for (i = SLJIT_S0; i >= tmp; i--) 11201.3Salnsn pop |= 1 << reg_map[i]; 11211.3Salnsn 11221.3Salnsn for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) 11231.3Salnsn pop |= 1 << reg_map[i]; 11241.3Salnsn 11251.3Salnsn return (pop & 0xff00) 11261.1Salnsn ? push_inst32(compiler, POP_W | (1 << 15) | pop) 11271.3Salnsn : push_inst16(compiler, POP | (1 << 8) | pop); 11281.1Salnsn} 11291.1Salnsn 11301.1Salnsn/* --------------------------------------------------------------------- */ 11311.1Salnsn/* Operators */ 11321.1Salnsn/* --------------------------------------------------------------------- */ 11331.1Salnsn 11341.1Salnsn#ifdef __cplusplus 11351.1Salnsnextern "C" { 11361.1Salnsn#endif 11371.1Salnsn 11381.1Salnsn#if defined(__GNUC__) 11391.1Salnsnextern unsigned int __aeabi_uidivmod(unsigned int numerator, int unsigned denominator); 11401.1Salnsnextern int __aeabi_idivmod(int numerator, int denominator); 11411.1Salnsn#else 11421.1Salnsn#error "Software divmod functions are needed" 11431.1Salnsn#endif 11441.1Salnsn 11451.1Salnsn#ifdef __cplusplus 11461.1Salnsn} 11471.1Salnsn#endif 11481.1Salnsn 11491.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) 11501.1Salnsn{ 11511.3Salnsn sljit_sw saved_reg_list[3]; 11521.3Salnsn sljit_sw saved_reg_count; 11531.3Salnsn 11541.1Salnsn CHECK_ERROR(); 11551.3Salnsn CHECK(check_sljit_emit_op0(compiler, op)); 11561.1Salnsn 11571.1Salnsn op = GET_OPCODE(op); 11581.1Salnsn switch (op) { 11591.1Salnsn case SLJIT_BREAKPOINT: 11601.1Salnsn return push_inst16(compiler, BKPT); 11611.1Salnsn case SLJIT_NOP: 11621.1Salnsn return push_inst16(compiler, NOP); 11631.3Salnsn case SLJIT_LMUL_UW: 11641.3Salnsn case SLJIT_LMUL_SW: 11651.3Salnsn return push_inst32(compiler, (op == SLJIT_LMUL_UW ? UMULL : SMULL) 11661.3Salnsn | (reg_map[SLJIT_R1] << 8) 11671.3Salnsn | (reg_map[SLJIT_R0] << 12) 11681.3Salnsn | (reg_map[SLJIT_R0] << 16) 11691.3Salnsn | reg_map[SLJIT_R1]); 11701.3Salnsn case SLJIT_DIVMOD_UW: 11711.3Salnsn case SLJIT_DIVMOD_SW: 11721.3Salnsn case SLJIT_DIV_UW: 11731.3Salnsn case SLJIT_DIV_SW: 11741.3Salnsn SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments); 11751.4Salnsn SLJIT_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 12); 11761.3Salnsn 11771.3Salnsn saved_reg_count = 0; 11781.3Salnsn if (compiler->scratches >= 4) 11791.3Salnsn saved_reg_list[saved_reg_count++] = 12; 11801.3Salnsn if (compiler->scratches >= 3) 11811.3Salnsn saved_reg_list[saved_reg_count++] = 2; 11821.3Salnsn if (op >= SLJIT_DIV_UW) 11831.3Salnsn saved_reg_list[saved_reg_count++] = 1; 11841.3Salnsn 11851.3Salnsn if (saved_reg_count > 0) { 11861.3Salnsn FAIL_IF(push_inst32(compiler, 0xf84d0d00 | (saved_reg_count >= 3 ? 16 : 8) 11871.3Salnsn | (saved_reg_list[0] << 12) /* str rX, [sp, #-8/-16]! */)); 11881.3Salnsn if (saved_reg_count >= 2) { 11891.3Salnsn SLJIT_ASSERT(saved_reg_list[1] < 8); 11901.3Salnsn FAIL_IF(push_inst16(compiler, 0x9001 | (saved_reg_list[1] << 8) /* str rX, [sp, #4] */)); 11911.3Salnsn } 11921.3Salnsn if (saved_reg_count >= 3) { 11931.3Salnsn SLJIT_ASSERT(saved_reg_list[2] < 8); 11941.3Salnsn FAIL_IF(push_inst16(compiler, 0x9002 | (saved_reg_list[2] << 8) /* str rX, [sp, #8] */)); 11951.3Salnsn } 11961.3Salnsn } 11971.3Salnsn 11981.1Salnsn#if defined(__GNUC__) 11991.1Salnsn FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM, 12001.3Salnsn ((op | 0x2) == SLJIT_DIV_UW ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod)))); 12011.1Salnsn#else 12021.1Salnsn#error "Software divmod functions are needed" 12031.1Salnsn#endif 12041.3Salnsn 12051.3Salnsn if (saved_reg_count > 0) { 12061.3Salnsn if (saved_reg_count >= 3) { 12071.3Salnsn SLJIT_ASSERT(saved_reg_list[2] < 8); 12081.3Salnsn FAIL_IF(push_inst16(compiler, 0x9802 | (saved_reg_list[2] << 8) /* ldr rX, [sp, #8] */)); 12091.3Salnsn } 12101.3Salnsn if (saved_reg_count >= 2) { 12111.3Salnsn SLJIT_ASSERT(saved_reg_list[1] < 8); 12121.3Salnsn FAIL_IF(push_inst16(compiler, 0x9801 | (saved_reg_list[1] << 8) /* ldr rX, [sp, #4] */)); 12131.3Salnsn } 12141.3Salnsn return push_inst32(compiler, 0xf85d0b00 | (saved_reg_count >= 3 ? 16 : 8) 12151.3Salnsn | (saved_reg_list[0] << 12) /* ldr rX, [sp], #8/16 */); 12161.3Salnsn } 12171.1Salnsn return SLJIT_SUCCESS; 12181.1Salnsn } 12191.1Salnsn 12201.1Salnsn return SLJIT_SUCCESS; 12211.1Salnsn} 12221.1Salnsn 12231.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, 12241.3Salnsn sljit_s32 dst, sljit_sw dstw, 12251.3Salnsn sljit_s32 src, sljit_sw srcw) 12261.1Salnsn{ 12271.3Salnsn sljit_s32 dst_r, flags; 12281.3Salnsn sljit_s32 op_flags = GET_ALL_FLAGS(op); 12291.1Salnsn 12301.1Salnsn CHECK_ERROR(); 12311.3Salnsn CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw)); 12321.1Salnsn ADJUST_LOCAL_OFFSET(dst, dstw); 12331.1Salnsn ADJUST_LOCAL_OFFSET(src, srcw); 12341.1Salnsn 12351.1Salnsn dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1; 12361.1Salnsn 12371.1Salnsn op = GET_OPCODE(op); 12381.1Salnsn if (op >= SLJIT_MOV && op <= SLJIT_MOVU_P) { 12391.1Salnsn switch (op) { 12401.1Salnsn case SLJIT_MOV: 12411.3Salnsn case SLJIT_MOV_U32: 12421.3Salnsn case SLJIT_MOV_S32: 12431.1Salnsn case SLJIT_MOV_P: 12441.1Salnsn flags = WORD_SIZE; 12451.1Salnsn break; 12461.3Salnsn case SLJIT_MOV_U8: 12471.1Salnsn flags = BYTE_SIZE; 12481.1Salnsn if (src & SLJIT_IMM) 12491.3Salnsn srcw = (sljit_u8)srcw; 12501.1Salnsn break; 12511.3Salnsn case SLJIT_MOV_S8: 12521.1Salnsn flags = BYTE_SIZE | SIGNED; 12531.1Salnsn if (src & SLJIT_IMM) 12541.3Salnsn srcw = (sljit_s8)srcw; 12551.1Salnsn break; 12561.3Salnsn case SLJIT_MOV_U16: 12571.1Salnsn flags = HALF_SIZE; 12581.1Salnsn if (src & SLJIT_IMM) 12591.3Salnsn srcw = (sljit_u16)srcw; 12601.1Salnsn break; 12611.3Salnsn case SLJIT_MOV_S16: 12621.1Salnsn flags = HALF_SIZE | SIGNED; 12631.1Salnsn if (src & SLJIT_IMM) 12641.3Salnsn srcw = (sljit_s16)srcw; 12651.1Salnsn break; 12661.1Salnsn case SLJIT_MOVU: 12671.3Salnsn case SLJIT_MOVU_U32: 12681.3Salnsn case SLJIT_MOVU_S32: 12691.1Salnsn case SLJIT_MOVU_P: 12701.1Salnsn flags = WORD_SIZE | UPDATE; 12711.1Salnsn break; 12721.3Salnsn case SLJIT_MOVU_U8: 12731.1Salnsn flags = BYTE_SIZE | UPDATE; 12741.1Salnsn if (src & SLJIT_IMM) 12751.3Salnsn srcw = (sljit_u8)srcw; 12761.1Salnsn break; 12771.3Salnsn case SLJIT_MOVU_S8: 12781.1Salnsn flags = BYTE_SIZE | SIGNED | UPDATE; 12791.1Salnsn if (src & SLJIT_IMM) 12801.3Salnsn srcw = (sljit_s8)srcw; 12811.1Salnsn break; 12821.3Salnsn case SLJIT_MOVU_U16: 12831.1Salnsn flags = HALF_SIZE | UPDATE; 12841.1Salnsn if (src & SLJIT_IMM) 12851.3Salnsn srcw = (sljit_u16)srcw; 12861.1Salnsn break; 12871.3Salnsn case SLJIT_MOVU_S16: 12881.1Salnsn flags = HALF_SIZE | SIGNED | UPDATE; 12891.1Salnsn if (src & SLJIT_IMM) 12901.3Salnsn srcw = (sljit_s16)srcw; 12911.1Salnsn break; 12921.1Salnsn default: 12931.4Salnsn SLJIT_UNREACHABLE(); 12941.1Salnsn flags = 0; 12951.1Salnsn break; 12961.1Salnsn } 12971.1Salnsn 12981.1Salnsn if (src & SLJIT_IMM) 12991.4Salnsn FAIL_IF(emit_op_imm(compiler, SLJIT_MOV | ARG2_IMM, dst_r, TMP_REG2, srcw)); 13001.1Salnsn else if (src & SLJIT_MEM) { 13011.4Salnsn FAIL_IF(emit_op_mem(compiler, flags, dst_r, src, srcw, ((flags & UPDATE) && dst_r == TMP_REG1) ? TMP_REG2 : TMP_REG1)); 13021.1Salnsn } else { 13031.1Salnsn if (dst_r != TMP_REG1) 13041.4Salnsn return emit_op_imm(compiler, op, dst_r, TMP_REG2, src); 13051.1Salnsn dst_r = src; 13061.1Salnsn } 13071.1Salnsn 13081.4Salnsn if (!(dst & SLJIT_MEM)) 13091.4Salnsn return SLJIT_SUCCESS; 13101.4Salnsn 13111.4Salnsn return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, (dst_r == TMP_REG1) ? TMP_REG2 : TMP_REG1); 13121.1Salnsn } 13131.1Salnsn 13141.1Salnsn if (op == SLJIT_NEG) { 13151.3Salnsn#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \ 13161.3Salnsn || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) 13171.1Salnsn compiler->skip_checks = 1; 13181.1Salnsn#endif 13191.1Salnsn return sljit_emit_op2(compiler, SLJIT_SUB | op_flags, dst, dstw, SLJIT_IMM, 0, src, srcw); 13201.1Salnsn } 13211.1Salnsn 13221.4Salnsn flags = HAS_FLAGS(op_flags) ? SET_FLAGS : 0; 13231.1Salnsn 13241.1Salnsn if (src & SLJIT_IMM) 13251.1Salnsn flags |= ARG2_IMM; 13261.4Salnsn else if (src & SLJIT_MEM) { 13271.4Salnsn FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1)); 13281.4Salnsn srcw = TMP_REG1; 13291.4Salnsn } 13301.1Salnsn else 13311.1Salnsn srcw = src; 13321.1Salnsn 13331.4Salnsn emit_op_imm(compiler, flags | op, dst_r, TMP_REG2, srcw); 13341.1Salnsn 13351.4Salnsn if (!(dst & SLJIT_MEM)) 13361.4Salnsn return SLJIT_SUCCESS; 13371.4Salnsn return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG2); 13381.1Salnsn} 13391.1Salnsn 13401.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, 13411.3Salnsn sljit_s32 dst, sljit_sw dstw, 13421.3Salnsn sljit_s32 src1, sljit_sw src1w, 13431.3Salnsn sljit_s32 src2, sljit_sw src2w) 13441.1Salnsn{ 13451.4Salnsn sljit_s32 dst_reg, flags, src2_reg; 13461.1Salnsn 13471.1Salnsn CHECK_ERROR(); 13481.3Salnsn CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); 13491.1Salnsn ADJUST_LOCAL_OFFSET(dst, dstw); 13501.1Salnsn ADJUST_LOCAL_OFFSET(src1, src1w); 13511.1Salnsn ADJUST_LOCAL_OFFSET(src2, src2w); 13521.1Salnsn 13531.4Salnsn dst_reg = SLOW_IS_REG(dst) ? dst : TMP_REG1; 13541.4Salnsn flags = HAS_FLAGS(op) ? SET_FLAGS : 0; 13551.1Salnsn 13561.1Salnsn if (src1 & SLJIT_IMM) 13571.1Salnsn flags |= ARG1_IMM; 13581.4Salnsn else if (src1 & SLJIT_MEM) { 13591.4Salnsn emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG1); 13601.4Salnsn src1w = TMP_REG1; 13611.4Salnsn } 13621.1Salnsn else 13631.1Salnsn src1w = src1; 13641.4Salnsn 13651.1Salnsn if (src2 & SLJIT_IMM) 13661.1Salnsn flags |= ARG2_IMM; 13671.4Salnsn else if (src2 & SLJIT_MEM) { 13681.4Salnsn src2_reg = (!(flags & ARG1_IMM) && (src1w == TMP_REG1)) ? TMP_REG2 : TMP_REG1; 13691.4Salnsn emit_op_mem(compiler, WORD_SIZE, src2_reg, src2, src2w, src2_reg); 13701.4Salnsn src2w = src2_reg; 13711.4Salnsn } 13721.1Salnsn else 13731.1Salnsn src2w = src2; 13741.1Salnsn 13751.1Salnsn if (dst == SLJIT_UNUSED) 13761.1Salnsn flags |= UNUSED_RETURN; 13771.1Salnsn 13781.4Salnsn emit_op_imm(compiler, flags | GET_OPCODE(op), dst_reg, src1w, src2w); 13791.1Salnsn 13801.4Salnsn if (!(dst & SLJIT_MEM)) 13811.4Salnsn return SLJIT_SUCCESS; 13821.4Salnsn return emit_op_mem(compiler, WORD_SIZE | STORE, dst_reg, dst, dstw, TMP_REG2); 13831.1Salnsn} 13841.1Salnsn 13851.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg) 13861.1Salnsn{ 13871.3Salnsn CHECK_REG_INDEX(check_sljit_get_register_index(reg)); 13881.1Salnsn return reg_map[reg]; 13891.1Salnsn} 13901.1Salnsn 13911.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg) 13921.1Salnsn{ 13931.3Salnsn CHECK_REG_INDEX(check_sljit_get_float_register_index(reg)); 13941.3Salnsn return reg << 1; 13951.1Salnsn} 13961.1Salnsn 13971.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, 13981.3Salnsn void *instruction, sljit_s32 size) 13991.1Salnsn{ 14001.1Salnsn CHECK_ERROR(); 14011.3Salnsn CHECK(check_sljit_emit_op_custom(compiler, instruction, size)); 14021.1Salnsn 14031.1Salnsn if (size == 2) 14041.3Salnsn return push_inst16(compiler, *(sljit_u16*)instruction); 14051.1Salnsn return push_inst32(compiler, *(sljit_ins*)instruction); 14061.1Salnsn} 14071.1Salnsn 14081.1Salnsn/* --------------------------------------------------------------------- */ 14091.1Salnsn/* Floating point operators */ 14101.1Salnsn/* --------------------------------------------------------------------- */ 14111.1Salnsn 14121.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_is_fpu_available(void) 14131.1Salnsn{ 14141.1Salnsn#ifdef SLJIT_IS_FPU_AVAILABLE 14151.1Salnsn return SLJIT_IS_FPU_AVAILABLE; 14161.1Salnsn#else 14171.1Salnsn /* Available by default. */ 14181.1Salnsn return 1; 14191.1Salnsn#endif 14201.1Salnsn} 14211.1Salnsn 14221.1Salnsn#define FPU_LOAD (1 << 20) 14231.1Salnsn 14241.3Salnsnstatic sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw) 14251.1Salnsn{ 14261.1Salnsn sljit_uw imm; 14271.3Salnsn sljit_sw inst = VSTR_F32 | (flags & (SLJIT_F32_OP | FPU_LOAD)); 14281.1Salnsn 14291.1Salnsn SLJIT_ASSERT(arg & SLJIT_MEM); 14301.1Salnsn 14311.1Salnsn /* Fast loads and stores. */ 14321.1Salnsn if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { 14331.4Salnsn FAIL_IF(push_inst32(compiler, ADD_W | RD4(TMP_REG1) | RN4(arg & REG_MASK) | RM4(OFFS_REG(arg)) | ((argw & 0x3) << 6))); 14341.4Salnsn arg = SLJIT_MEM | TMP_REG1; 14351.1Salnsn argw = 0; 14361.1Salnsn } 14371.1Salnsn 14381.1Salnsn if ((arg & REG_MASK) && (argw & 0x3) == 0) { 14391.1Salnsn if (!(argw & ~0x3fc)) 14401.1Salnsn return push_inst32(compiler, inst | 0x800000 | RN4(arg & REG_MASK) | DD4(reg) | (argw >> 2)); 14411.1Salnsn if (!(-argw & ~0x3fc)) 14421.1Salnsn return push_inst32(compiler, inst | RN4(arg & REG_MASK) | DD4(reg) | (-argw >> 2)); 14431.1Salnsn } 14441.1Salnsn 14451.1Salnsn if (arg & REG_MASK) { 14461.1Salnsn if (emit_set_delta(compiler, TMP_REG1, arg & REG_MASK, argw) != SLJIT_ERR_UNSUPPORTED) { 14471.1Salnsn FAIL_IF(compiler->error); 14481.1Salnsn return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg)); 14491.1Salnsn } 14501.1Salnsn imm = get_imm(argw & ~0x3fc); 14511.1Salnsn if (imm != INVALID_IMM) { 14521.1Salnsn FAIL_IF(push_inst32(compiler, ADD_WI | RD4(TMP_REG1) | RN4(arg & REG_MASK) | imm)); 14531.1Salnsn return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg) | ((argw & 0x3fc) >> 2)); 14541.1Salnsn } 14551.1Salnsn imm = get_imm(-argw & ~0x3fc); 14561.1Salnsn if (imm != INVALID_IMM) { 14571.1Salnsn argw = -argw; 14581.1Salnsn FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(arg & REG_MASK) | imm)); 14591.1Salnsn return push_inst32(compiler, inst | RN4(TMP_REG1) | DD4(reg) | ((argw & 0x3fc) >> 2)); 14601.1Salnsn } 14611.1Salnsn } 14621.1Salnsn 14631.4Salnsn FAIL_IF(load_immediate(compiler, TMP_REG1, argw)); 14641.1Salnsn if (arg & REG_MASK) 14651.4Salnsn FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(TMP_REG1, (arg & REG_MASK)))); 14661.4Salnsn return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg)); 14671.1Salnsn} 14681.1Salnsn 14691.3Salnsnstatic SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, 14701.3Salnsn sljit_s32 dst, sljit_sw dstw, 14711.3Salnsn sljit_s32 src, sljit_sw srcw) 14721.3Salnsn{ 14731.4Salnsn op ^= SLJIT_F32_OP; 14741.4Salnsn 14751.3Salnsn if (src & SLJIT_MEM) { 14761.3Salnsn FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src, srcw)); 14771.3Salnsn src = TMP_FREG1; 14781.3Salnsn } 14791.3Salnsn 14801.3Salnsn FAIL_IF(push_inst32(compiler, VCVT_S32_F32 | (op & SLJIT_F32_OP) | DD4(TMP_FREG1) | DM4(src))); 14811.3Salnsn 14821.3Salnsn if (dst == SLJIT_UNUSED) 14831.3Salnsn return SLJIT_SUCCESS; 14841.3Salnsn 14851.3Salnsn if (FAST_IS_REG(dst)) 14861.3Salnsn return push_inst32(compiler, VMOV | (1 << 20) | RT4(dst) | DN4(TMP_FREG1)); 14871.3Salnsn 14881.3Salnsn /* Store the integer value from a VFP register. */ 14891.3Salnsn return emit_fop_mem(compiler, 0, TMP_FREG1, dst, dstw); 14901.3Salnsn} 14911.3Salnsn 14921.3Salnsnstatic SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op, 14931.3Salnsn sljit_s32 dst, sljit_sw dstw, 14941.3Salnsn sljit_s32 src, sljit_sw srcw) 14951.1Salnsn{ 14961.3Salnsn sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; 14971.3Salnsn 14981.4Salnsn op ^= SLJIT_F32_OP; 14991.4Salnsn 15001.3Salnsn if (FAST_IS_REG(src)) 15011.3Salnsn FAIL_IF(push_inst32(compiler, VMOV | RT4(src) | DN4(TMP_FREG1))); 15021.3Salnsn else if (src & SLJIT_MEM) { 15031.3Salnsn /* Load the integer value into a VFP register. */ 15041.3Salnsn FAIL_IF(emit_fop_mem(compiler, FPU_LOAD, TMP_FREG1, src, srcw)); 15051.3Salnsn } 15061.3Salnsn else { 15071.3Salnsn FAIL_IF(load_immediate(compiler, TMP_REG1, srcw)); 15081.3Salnsn FAIL_IF(push_inst32(compiler, VMOV | RT4(TMP_REG1) | DN4(TMP_FREG1))); 15091.3Salnsn } 15101.3Salnsn 15111.3Salnsn FAIL_IF(push_inst32(compiler, VCVT_F32_S32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(TMP_FREG1))); 15121.3Salnsn 15131.3Salnsn if (dst & SLJIT_MEM) 15141.3Salnsn return emit_fop_mem(compiler, (op & SLJIT_F32_OP), TMP_FREG1, dst, dstw); 15151.3Salnsn return SLJIT_SUCCESS; 15161.3Salnsn} 15171.3Salnsn 15181.3Salnsnstatic SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op, 15191.3Salnsn sljit_s32 src1, sljit_sw src1w, 15201.3Salnsn sljit_s32 src2, sljit_sw src2w) 15211.3Salnsn{ 15221.4Salnsn op ^= SLJIT_F32_OP; 15231.4Salnsn 15241.3Salnsn if (src1 & SLJIT_MEM) { 15251.3Salnsn emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src1, src1w); 15261.3Salnsn src1 = TMP_FREG1; 15271.3Salnsn } 15281.3Salnsn 15291.3Salnsn if (src2 & SLJIT_MEM) { 15301.3Salnsn emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG2, src2, src2w); 15311.3Salnsn src2 = TMP_FREG2; 15321.3Salnsn } 15331.3Salnsn 15341.3Salnsn FAIL_IF(push_inst32(compiler, VCMP_F32 | (op & SLJIT_F32_OP) | DD4(src1) | DM4(src2))); 15351.3Salnsn return push_inst32(compiler, VMRS); 15361.3Salnsn} 15371.3Salnsn 15381.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, 15391.3Salnsn sljit_s32 dst, sljit_sw dstw, 15401.3Salnsn sljit_s32 src, sljit_sw srcw) 15411.3Salnsn{ 15421.3Salnsn sljit_s32 dst_r; 15431.1Salnsn 15441.1Salnsn CHECK_ERROR(); 15451.3Salnsn 15461.3Salnsn SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100), float_transfer_bit_error); 15471.3Salnsn SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw); 15481.1Salnsn 15491.3Salnsn dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; 15501.1Salnsn 15511.4Salnsn if (GET_OPCODE(op) != SLJIT_CONV_F64_FROM_F32) 15521.4Salnsn op ^= SLJIT_F32_OP; 15531.4Salnsn 15541.1Salnsn if (src & SLJIT_MEM) { 15551.3Salnsn emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, dst_r, src, srcw); 15561.1Salnsn src = dst_r; 15571.1Salnsn } 15581.1Salnsn 15591.1Salnsn switch (GET_OPCODE(op)) { 15601.3Salnsn case SLJIT_MOV_F64: 15611.3Salnsn if (src != dst_r) { 15621.3Salnsn if (dst_r != TMP_FREG1) 15631.3Salnsn FAIL_IF(push_inst32(compiler, VMOV_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src))); 15641.3Salnsn else 15651.3Salnsn dst_r = src; 15661.3Salnsn } 15671.1Salnsn break; 15681.3Salnsn case SLJIT_NEG_F64: 15691.3Salnsn FAIL_IF(push_inst32(compiler, VNEG_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src))); 15701.1Salnsn break; 15711.3Salnsn case SLJIT_ABS_F64: 15721.3Salnsn FAIL_IF(push_inst32(compiler, VABS_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src))); 15731.3Salnsn break; 15741.3Salnsn case SLJIT_CONV_F64_FROM_F32: 15751.3Salnsn FAIL_IF(push_inst32(compiler, VCVT_F64_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src))); 15761.3Salnsn op ^= SLJIT_F32_OP; 15771.1Salnsn break; 15781.1Salnsn } 15791.1Salnsn 15801.3Salnsn if (dst & SLJIT_MEM) 15811.3Salnsn return emit_fop_mem(compiler, (op & SLJIT_F32_OP), dst_r, dst, dstw); 15821.3Salnsn return SLJIT_SUCCESS; 15831.1Salnsn} 15841.1Salnsn 15851.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, 15861.3Salnsn sljit_s32 dst, sljit_sw dstw, 15871.3Salnsn sljit_s32 src1, sljit_sw src1w, 15881.3Salnsn sljit_s32 src2, sljit_sw src2w) 15891.1Salnsn{ 15901.3Salnsn sljit_s32 dst_r; 15911.1Salnsn 15921.1Salnsn CHECK_ERROR(); 15931.3Salnsn CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); 15941.3Salnsn ADJUST_LOCAL_OFFSET(dst, dstw); 15951.3Salnsn ADJUST_LOCAL_OFFSET(src1, src1w); 15961.3Salnsn ADJUST_LOCAL_OFFSET(src2, src2w); 15971.1Salnsn 15981.3Salnsn op ^= SLJIT_F32_OP; 15991.1Salnsn 16001.3Salnsn dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; 16011.1Salnsn if (src1 & SLJIT_MEM) { 16021.3Salnsn emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src1, src1w); 16031.1Salnsn src1 = TMP_FREG1; 16041.1Salnsn } 16051.1Salnsn if (src2 & SLJIT_MEM) { 16061.3Salnsn emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG2, src2, src2w); 16071.1Salnsn src2 = TMP_FREG2; 16081.1Salnsn } 16091.1Salnsn 16101.1Salnsn switch (GET_OPCODE(op)) { 16111.3Salnsn case SLJIT_ADD_F64: 16121.3Salnsn FAIL_IF(push_inst32(compiler, VADD_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2))); 16131.1Salnsn break; 16141.3Salnsn case SLJIT_SUB_F64: 16151.3Salnsn FAIL_IF(push_inst32(compiler, VSUB_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2))); 16161.1Salnsn break; 16171.3Salnsn case SLJIT_MUL_F64: 16181.3Salnsn FAIL_IF(push_inst32(compiler, VMUL_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2))); 16191.1Salnsn break; 16201.3Salnsn case SLJIT_DIV_F64: 16211.3Salnsn FAIL_IF(push_inst32(compiler, VDIV_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2))); 16221.1Salnsn break; 16231.1Salnsn } 16241.1Salnsn 16251.1Salnsn if (!(dst & SLJIT_MEM)) 16261.1Salnsn return SLJIT_SUCCESS; 16271.3Salnsn return emit_fop_mem(compiler, (op & SLJIT_F32_OP), TMP_FREG1, dst, dstw); 16281.1Salnsn} 16291.1Salnsn 16301.1Salnsn#undef FPU_LOAD 16311.1Salnsn 16321.1Salnsn/* --------------------------------------------------------------------- */ 16331.1Salnsn/* Other instructions */ 16341.1Salnsn/* --------------------------------------------------------------------- */ 16351.1Salnsn 16361.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) 16371.1Salnsn{ 16381.1Salnsn CHECK_ERROR(); 16391.3Salnsn CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); 16401.1Salnsn ADJUST_LOCAL_OFFSET(dst, dstw); 16411.1Salnsn 16421.4Salnsn SLJIT_ASSERT(reg_map[TMP_REG2] == 14); 16431.4Salnsn 16441.1Salnsn /* For UNUSED dst. Uncommon, but possible. */ 16451.1Salnsn if (dst == SLJIT_UNUSED) 16461.1Salnsn return SLJIT_SUCCESS; 16471.1Salnsn 16481.3Salnsn if (FAST_IS_REG(dst)) 16491.4Salnsn return push_inst16(compiler, MOV | SET_REGS44(dst, TMP_REG2)); 16501.1Salnsn 16511.1Salnsn /* Memory. */ 16521.4Salnsn return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw, TMP_REG1); 16531.1Salnsn} 16541.1Salnsn 16551.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw) 16561.1Salnsn{ 16571.1Salnsn CHECK_ERROR(); 16581.3Salnsn CHECK(check_sljit_emit_fast_return(compiler, src, srcw)); 16591.1Salnsn ADJUST_LOCAL_OFFSET(src, srcw); 16601.1Salnsn 16611.4Salnsn SLJIT_ASSERT(reg_map[TMP_REG2] == 14); 16621.4Salnsn 16631.3Salnsn if (FAST_IS_REG(src)) 16641.4Salnsn FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG2, src))); 16651.1Salnsn else if (src & SLJIT_MEM) { 16661.4Salnsn FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src, srcw, TMP_REG2)); 16671.1Salnsn } 16681.1Salnsn else if (src & SLJIT_IMM) 16691.4Salnsn FAIL_IF(load_immediate(compiler, TMP_REG2, srcw)); 16701.4Salnsn return push_inst16(compiler, BX | RN3(TMP_REG2)); 16711.1Salnsn} 16721.1Salnsn 16731.1Salnsn/* --------------------------------------------------------------------- */ 16741.1Salnsn/* Conditional instructions */ 16751.1Salnsn/* --------------------------------------------------------------------- */ 16761.1Salnsn 16771.3Salnsnstatic sljit_uw get_cc(sljit_s32 type) 16781.1Salnsn{ 16791.1Salnsn switch (type) { 16801.3Salnsn case SLJIT_EQUAL: 16811.3Salnsn case SLJIT_MUL_NOT_OVERFLOW: 16821.3Salnsn case SLJIT_EQUAL_F64: 16831.1Salnsn return 0x0; 16841.1Salnsn 16851.3Salnsn case SLJIT_NOT_EQUAL: 16861.3Salnsn case SLJIT_MUL_OVERFLOW: 16871.3Salnsn case SLJIT_NOT_EQUAL_F64: 16881.1Salnsn return 0x1; 16891.1Salnsn 16901.3Salnsn case SLJIT_LESS: 16911.3Salnsn case SLJIT_LESS_F64: 16921.1Salnsn return 0x3; 16931.1Salnsn 16941.3Salnsn case SLJIT_GREATER_EQUAL: 16951.3Salnsn case SLJIT_GREATER_EQUAL_F64: 16961.1Salnsn return 0x2; 16971.1Salnsn 16981.3Salnsn case SLJIT_GREATER: 16991.3Salnsn case SLJIT_GREATER_F64: 17001.1Salnsn return 0x8; 17011.1Salnsn 17021.3Salnsn case SLJIT_LESS_EQUAL: 17031.3Salnsn case SLJIT_LESS_EQUAL_F64: 17041.1Salnsn return 0x9; 17051.1Salnsn 17061.3Salnsn case SLJIT_SIG_LESS: 17071.1Salnsn return 0xb; 17081.1Salnsn 17091.3Salnsn case SLJIT_SIG_GREATER_EQUAL: 17101.1Salnsn return 0xa; 17111.1Salnsn 17121.3Salnsn case SLJIT_SIG_GREATER: 17131.1Salnsn return 0xc; 17141.1Salnsn 17151.3Salnsn case SLJIT_SIG_LESS_EQUAL: 17161.1Salnsn return 0xd; 17171.1Salnsn 17181.3Salnsn case SLJIT_OVERFLOW: 17191.3Salnsn case SLJIT_UNORDERED_F64: 17201.1Salnsn return 0x6; 17211.1Salnsn 17221.3Salnsn case SLJIT_NOT_OVERFLOW: 17231.3Salnsn case SLJIT_ORDERED_F64: 17241.1Salnsn return 0x7; 17251.1Salnsn 17261.1Salnsn default: /* SLJIT_JUMP */ 17271.4Salnsn SLJIT_UNREACHABLE(); 17281.1Salnsn return 0xe; 17291.1Salnsn } 17301.1Salnsn} 17311.1Salnsn 17321.1SalnsnSLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler) 17331.1Salnsn{ 17341.1Salnsn struct sljit_label *label; 17351.1Salnsn 17361.1Salnsn CHECK_ERROR_PTR(); 17371.3Salnsn CHECK_PTR(check_sljit_emit_label(compiler)); 17381.1Salnsn 17391.1Salnsn if (compiler->last_label && compiler->last_label->size == compiler->size) 17401.1Salnsn return compiler->last_label; 17411.1Salnsn 17421.1Salnsn label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label)); 17431.1Salnsn PTR_FAIL_IF(!label); 17441.1Salnsn set_label(label, compiler); 17451.1Salnsn return label; 17461.1Salnsn} 17471.1Salnsn 17481.3SalnsnSLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type) 17491.1Salnsn{ 17501.1Salnsn struct sljit_jump *jump; 17511.1Salnsn sljit_ins cc; 17521.1Salnsn 17531.1Salnsn CHECK_ERROR_PTR(); 17541.3Salnsn CHECK_PTR(check_sljit_emit_jump(compiler, type)); 17551.1Salnsn 17561.1Salnsn jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); 17571.1Salnsn PTR_FAIL_IF(!jump); 17581.1Salnsn set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); 17591.1Salnsn type &= 0xff; 17601.1Salnsn 17611.1Salnsn /* In ARM, we don't need to touch the arguments. */ 17621.1Salnsn PTR_FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0)); 17631.1Salnsn if (type < SLJIT_JUMP) { 17641.1Salnsn jump->flags |= IS_COND; 17651.1Salnsn cc = get_cc(type); 17661.1Salnsn jump->flags |= cc << 8; 17671.1Salnsn PTR_FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); 17681.1Salnsn } 17691.1Salnsn 17701.1Salnsn jump->addr = compiler->size; 17711.1Salnsn if (type <= SLJIT_JUMP) 17721.1Salnsn PTR_FAIL_IF(push_inst16(compiler, BX | RN3(TMP_REG1))); 17731.1Salnsn else { 17741.1Salnsn jump->flags |= IS_BL; 17751.1Salnsn PTR_FAIL_IF(push_inst16(compiler, BLX | RN3(TMP_REG1))); 17761.1Salnsn } 17771.1Salnsn 17781.1Salnsn return jump; 17791.1Salnsn} 17801.1Salnsn 17811.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw) 17821.1Salnsn{ 17831.1Salnsn struct sljit_jump *jump; 17841.1Salnsn 17851.1Salnsn CHECK_ERROR(); 17861.3Salnsn CHECK(check_sljit_emit_ijump(compiler, type, src, srcw)); 17871.1Salnsn ADJUST_LOCAL_OFFSET(src, srcw); 17881.1Salnsn 17891.1Salnsn /* In ARM, we don't need to touch the arguments. */ 17901.1Salnsn if (!(src & SLJIT_IMM)) { 17911.1Salnsn if (FAST_IS_REG(src)) 17921.1Salnsn return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(src)); 17931.1Salnsn 17941.4Salnsn FAIL_IF(emit_op_mem(compiler, WORD_SIZE, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, src, srcw, TMP_REG1)); 17951.1Salnsn if (type >= SLJIT_FAST_CALL) 17961.1Salnsn return push_inst16(compiler, BLX | RN3(TMP_REG1)); 17971.1Salnsn } 17981.1Salnsn 17991.1Salnsn jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); 18001.1Salnsn FAIL_IF(!jump); 18011.1Salnsn set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0)); 18021.1Salnsn jump->u.target = srcw; 18031.1Salnsn 18041.1Salnsn FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0)); 18051.1Salnsn jump->addr = compiler->size; 18061.1Salnsn return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(TMP_REG1)); 18071.1Salnsn} 18081.1Salnsn 18091.3SalnsnSLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, 18101.3Salnsn sljit_s32 dst, sljit_sw dstw, 18111.3Salnsn sljit_s32 src, sljit_sw srcw, 18121.3Salnsn sljit_s32 type) 18131.1Salnsn{ 18141.3Salnsn sljit_s32 dst_r, flags = GET_ALL_FLAGS(op); 18151.1Salnsn sljit_ins cc, ins; 18161.1Salnsn 18171.1Salnsn CHECK_ERROR(); 18181.3Salnsn CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type)); 18191.1Salnsn ADJUST_LOCAL_OFFSET(dst, dstw); 18201.1Salnsn ADJUST_LOCAL_OFFSET(src, srcw); 18211.1Salnsn 18221.1Salnsn if (dst == SLJIT_UNUSED) 18231.1Salnsn return SLJIT_SUCCESS; 18241.1Salnsn 18251.1Salnsn op = GET_OPCODE(op); 18261.3Salnsn cc = get_cc(type & 0xff); 18271.4Salnsn dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; 18281.1Salnsn 18291.1Salnsn if (op < SLJIT_ADD) { 18301.1Salnsn FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4)); 18311.1Salnsn if (reg_map[dst_r] > 7) { 18321.1Salnsn FAIL_IF(push_inst32(compiler, MOV_WI | RD4(dst_r) | 1)); 18331.1Salnsn FAIL_IF(push_inst32(compiler, MOV_WI | RD4(dst_r) | 0)); 18341.1Salnsn } else { 18351.1Salnsn FAIL_IF(push_inst16(compiler, MOVSI | RDN3(dst_r) | 1)); 18361.1Salnsn FAIL_IF(push_inst16(compiler, MOVSI | RDN3(dst_r) | 0)); 18371.1Salnsn } 18381.4Salnsn if (dst_r != TMP_REG1) 18391.1Salnsn return SLJIT_SUCCESS; 18401.4Salnsn return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG1, dst, dstw, TMP_REG2); 18411.1Salnsn } 18421.1Salnsn 18431.1Salnsn ins = (op == SLJIT_AND ? ANDI : (op == SLJIT_OR ? ORRI : EORI)); 18441.4Salnsn 18451.1Salnsn if ((op == SLJIT_OR || op == SLJIT_XOR) && FAST_IS_REG(dst) && dst == src) { 18461.1Salnsn /* Does not change the other bits. */ 18471.1Salnsn FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); 18481.1Salnsn FAIL_IF(push_inst32(compiler, ins | RN4(src) | RD4(dst) | 1)); 18491.4Salnsn if (flags & SLJIT_SET_Z) { 18501.1Salnsn /* The condition must always be set, even if the ORRI/EORI is not executed above. */ 18511.1Salnsn if (reg_map[dst] <= 7) 18521.1Salnsn return push_inst16(compiler, MOVS | RD3(TMP_REG1) | RN3(dst)); 18531.1Salnsn return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(TMP_REG1) | RM4(dst)); 18541.1Salnsn } 18551.1Salnsn return SLJIT_SUCCESS; 18561.1Salnsn } 18571.1Salnsn 18581.1Salnsn if (src & SLJIT_MEM) { 18591.4Salnsn FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src, srcw, TMP_REG2)); 18601.1Salnsn src = TMP_REG2; 18611.1Salnsn srcw = 0; 18621.1Salnsn } else if (src & SLJIT_IMM) { 18631.1Salnsn FAIL_IF(load_immediate(compiler, TMP_REG2, srcw)); 18641.1Salnsn src = TMP_REG2; 18651.1Salnsn srcw = 0; 18661.1Salnsn } 18671.1Salnsn 18681.1Salnsn if (op == SLJIT_AND || src != dst_r) { 18691.1Salnsn FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4)); 18701.1Salnsn FAIL_IF(push_inst32(compiler, ins | RN4(src) | RD4(dst_r) | 1)); 18711.1Salnsn FAIL_IF(push_inst32(compiler, ins | RN4(src) | RD4(dst_r) | 0)); 18721.1Salnsn } 18731.1Salnsn else { 18741.1Salnsn FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); 18751.1Salnsn FAIL_IF(push_inst32(compiler, ins | RN4(src) | RD4(dst_r) | 1)); 18761.1Salnsn } 18771.1Salnsn 18781.4Salnsn if (dst_r == TMP_REG1) 18791.4Salnsn FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG1, dst, dstw, TMP_REG2)); 18801.1Salnsn 18811.4Salnsn if (flags & SLJIT_SET_Z) { 18821.1Salnsn /* The condition must always be set, even if the ORR/EORI is not executed above. */ 18831.1Salnsn if (reg_map[dst_r] <= 7) 18841.1Salnsn return push_inst16(compiler, MOVS | RD3(TMP_REG1) | RN3(dst_r)); 18851.1Salnsn return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(TMP_REG1) | RM4(dst_r)); 18861.1Salnsn } 18871.1Salnsn return SLJIT_SUCCESS; 18881.1Salnsn} 18891.1Salnsn 18901.3SalnsnSLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value) 18911.1Salnsn{ 18921.1Salnsn struct sljit_const *const_; 18931.3Salnsn sljit_s32 dst_r; 18941.1Salnsn 18951.1Salnsn CHECK_ERROR_PTR(); 18961.3Salnsn CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value)); 18971.1Salnsn ADJUST_LOCAL_OFFSET(dst, dstw); 18981.1Salnsn 18991.1Salnsn const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const)); 19001.1Salnsn PTR_FAIL_IF(!const_); 19011.1Salnsn set_const(const_, compiler); 19021.1Salnsn 19031.1Salnsn dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1; 19041.1Salnsn PTR_FAIL_IF(emit_imm32_const(compiler, dst_r, init_value)); 19051.1Salnsn 19061.1Salnsn if (dst & SLJIT_MEM) 19071.4Salnsn PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2)); 19081.1Salnsn return const_; 19091.1Salnsn} 19101.1Salnsn 19111.4SalnsnSLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) 19121.1Salnsn{ 19131.3Salnsn sljit_u16 *inst = (sljit_u16*)addr; 19141.4Salnsn modify_imm32_const(inst, new_target); 19151.4Salnsn inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); 19161.1Salnsn SLJIT_CACHE_FLUSH(inst, inst + 4); 19171.1Salnsn} 19181.1Salnsn 19191.4SalnsnSLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) 19201.1Salnsn{ 19211.3Salnsn sljit_u16 *inst = (sljit_u16*)addr; 19221.1Salnsn modify_imm32_const(inst, new_constant); 19231.4Salnsn inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); 19241.1Salnsn SLJIT_CACHE_FLUSH(inst, inst + 4); 19251.1Salnsn} 1926