Annotation of win32/pcre/sljit/sljitNativeARM_v5.c, revision 1.1
1.1 ! misha 1: /*
! 2: * Stack-less Just-In-Time compiler
! 3: *
! 4: * Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without modification, are
! 7: * permitted provided that the following conditions are met:
! 8: *
! 9: * 1. Redistributions of source code must retain the above copyright notice, this list of
! 10: * conditions and the following disclaimer.
! 11: *
! 12: * 2. Redistributions in binary form must reproduce the above copyright notice, this list
! 13: * of conditions and the following disclaimer in the documentation and/or other materials
! 14: * provided with the distribution.
! 15: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
! 17: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
! 19: * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
! 20: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
! 21: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
! 22: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 23: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 24: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 25: */
! 26:
! 27: SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name()
! 28: {
! 29: #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
! 30: return "ARMv7" SLJIT_CPUINFO;
! 31: #elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 32: return "ARMv5" SLJIT_CPUINFO;
! 33: #else
! 34: #error "Internal error: Unknown ARM architecture"
! 35: #endif
! 36: }
! 37:
! 38: /* Last register + 1. */
! 39: #define TMP_REG1 (SLJIT_NO_REGISTERS + 1)
! 40: #define TMP_REG2 (SLJIT_NO_REGISTERS + 2)
! 41: #define TMP_REG3 (SLJIT_NO_REGISTERS + 3)
! 42: #define TMP_PC (SLJIT_NO_REGISTERS + 4)
! 43:
! 44: #define TMP_FREG1 (SLJIT_FLOAT_REG4 + 1)
! 45: #define TMP_FREG2 (SLJIT_FLOAT_REG4 + 2)
! 46:
! 47: /* In ARM instruction words.
! 48: Cache lines are usually 32 byte aligned. */
! 49: #define CONST_POOL_ALIGNMENT 8
! 50: #define CONST_POOL_EMPTY 0xffffffff
! 51:
! 52: #define ALIGN_INSTRUCTION(ptr) \
! 53: (sljit_uw*)(((sljit_uw)(ptr) + (CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1) & ~((CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1))
! 54: #define MAX_DIFFERENCE(max_diff) \
! 55: (((max_diff) / (int)sizeof(sljit_uw)) - (CONST_POOL_ALIGNMENT - 1))
! 56:
! 57: /* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */
! 58: static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = {
! 59: 0, 0, 1, 2, 10, 11, 4, 5, 6, 7, 8, 13, 3, 12, 14, 15
! 60: };
! 61:
! 62: #define RM(rm) (reg_map[rm])
! 63: #define RD(rd) (reg_map[rd] << 12)
! 64: #define RN(rn) (reg_map[rn] << 16)
! 65:
! 66: /* --------------------------------------------------------------------- */
! 67: /* Instrucion forms */
! 68: /* --------------------------------------------------------------------- */
! 69:
! 70: /* The instruction includes the AL condition.
! 71: INST_NAME - CONDITIONAL remove this flag. */
! 72: #define COND_MASK 0xf0000000
! 73: #define CONDITIONAL 0xe0000000
! 74: #define PUSH_POOL 0xff000000
! 75:
! 76: /* DP - Data Processing instruction (use with EMIT_DATA_PROCESS_INS). */
! 77: #define ADC_DP 0x5
! 78: #define ADD_DP 0x4
! 79: #define AND_DP 0x0
! 80: #define B 0xea000000
! 81: #define BIC_DP 0xe
! 82: #define BL 0xeb000000
! 83: #define BLX 0xe12fff30
! 84: #define BX 0xe12fff10
! 85: #define CLZ 0xe16f0f10
! 86: #define CMP_DP 0xa
! 87: #define BKPT 0xe1200070
! 88: #define EOR_DP 0x1
! 89: #define MOV_DP 0xd
! 90: #define MUL 0xe0000090
! 91: #define MVN_DP 0xf
! 92: #define NOP 0xe1a00000
! 93: #define ORR_DP 0xc
! 94: #define PUSH 0xe92d0000
! 95: #define POP 0xe8bd0000
! 96: #define RSB_DP 0x3
! 97: #define RSC_DP 0x7
! 98: #define SBC_DP 0x6
! 99: #define SMULL 0xe0c00090
! 100: #define SUB_DP 0x2
! 101: #define UMULL 0xe0800090
! 102: #define VABS_F64 0xeeb00bc0
! 103: #define VADD_F64 0xee300b00
! 104: #define VCMP_F64 0xeeb40b40
! 105: #define VDIV_F64 0xee800b00
! 106: #define VMOV_F64 0xeeb00b40
! 107: #define VMRS 0xeef1fa10
! 108: #define VMUL_F64 0xee200b00
! 109: #define VNEG_F64 0xeeb10b40
! 110: #define VSTR 0xed000b00
! 111: #define VSUB_F64 0xee300b40
! 112:
! 113: #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
! 114: /* Arm v7 specific instructions. */
! 115: #define MOVW 0xe3000000
! 116: #define MOVT 0xe3400000
! 117: #define SXTB 0xe6af0070
! 118: #define SXTH 0xe6bf0070
! 119: #define UXTB 0xe6ef0070
! 120: #define UXTH 0xe6ff0070
! 121: #endif
! 122:
! 123: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 124:
! 125: static int push_cpool(struct sljit_compiler *compiler)
! 126: {
! 127: /* Pushing the constant pool into the instruction stream. */
! 128: sljit_uw* inst;
! 129: sljit_uw* cpool_ptr;
! 130: sljit_uw* cpool_end;
! 131: int i;
! 132:
! 133: /* The label could point the address after the constant pool. */
! 134: if (compiler->last_label && compiler->last_label->size == compiler->size)
! 135: compiler->last_label->size += compiler->cpool_fill + (CONST_POOL_ALIGNMENT - 1) + 1;
! 136:
! 137: SLJIT_ASSERT(compiler->cpool_fill > 0 && compiler->cpool_fill <= CPOOL_SIZE);
! 138: inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
! 139: FAIL_IF(!inst);
! 140: compiler->size++;
! 141: *inst = 0xff000000 | compiler->cpool_fill;
! 142:
! 143: for (i = 0; i < CONST_POOL_ALIGNMENT - 1; i++) {
! 144: inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
! 145: FAIL_IF(!inst);
! 146: compiler->size++;
! 147: *inst = 0;
! 148: }
! 149:
! 150: cpool_ptr = compiler->cpool;
! 151: cpool_end = cpool_ptr + compiler->cpool_fill;
! 152: while (cpool_ptr < cpool_end) {
! 153: inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
! 154: FAIL_IF(!inst);
! 155: compiler->size++;
! 156: *inst = *cpool_ptr++;
! 157: }
! 158: compiler->cpool_diff = CONST_POOL_EMPTY;
! 159: compiler->cpool_fill = 0;
! 160: return SLJIT_SUCCESS;
! 161: }
! 162:
! 163: static int push_inst(struct sljit_compiler *compiler, sljit_uw inst)
! 164: {
! 165: sljit_uw* ptr;
! 166:
! 167: if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)))
! 168: FAIL_IF(push_cpool(compiler));
! 169:
! 170: ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
! 171: FAIL_IF(!ptr);
! 172: compiler->size++;
! 173: *ptr = inst;
! 174: return SLJIT_SUCCESS;
! 175: }
! 176:
! 177: static int push_inst_with_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal)
! 178: {
! 179: sljit_uw* ptr;
! 180: sljit_uw cpool_index = CPOOL_SIZE;
! 181: sljit_uw* cpool_ptr;
! 182: sljit_uw* cpool_end;
! 183: sljit_ub* cpool_unique_ptr;
! 184:
! 185: if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)))
! 186: FAIL_IF(push_cpool(compiler));
! 187: else if (compiler->cpool_fill > 0) {
! 188: cpool_ptr = compiler->cpool;
! 189: cpool_end = cpool_ptr + compiler->cpool_fill;
! 190: cpool_unique_ptr = compiler->cpool_unique;
! 191: do {
! 192: if ((*cpool_ptr == literal) && !(*cpool_unique_ptr)) {
! 193: cpool_index = cpool_ptr - compiler->cpool;
! 194: break;
! 195: }
! 196: cpool_ptr++;
! 197: cpool_unique_ptr++;
! 198: } while (cpool_ptr < cpool_end);
! 199: }
! 200:
! 201: if (cpool_index == CPOOL_SIZE) {
! 202: /* Must allocate a new entry in the literal pool. */
! 203: if (compiler->cpool_fill < CPOOL_SIZE) {
! 204: cpool_index = compiler->cpool_fill;
! 205: compiler->cpool_fill++;
! 206: }
! 207: else {
! 208: FAIL_IF(push_cpool(compiler));
! 209: cpool_index = 0;
! 210: compiler->cpool_fill = 1;
! 211: }
! 212: }
! 213:
! 214: SLJIT_ASSERT((inst & 0xfff) == 0);
! 215: ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
! 216: FAIL_IF(!ptr);
! 217: compiler->size++;
! 218: *ptr = inst | cpool_index;
! 219:
! 220: compiler->cpool[cpool_index] = literal;
! 221: compiler->cpool_unique[cpool_index] = 0;
! 222: if (compiler->cpool_diff == CONST_POOL_EMPTY)
! 223: compiler->cpool_diff = compiler->size;
! 224: return SLJIT_SUCCESS;
! 225: }
! 226:
! 227: static int push_inst_with_unique_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal)
! 228: {
! 229: sljit_uw* ptr;
! 230: if (SLJIT_UNLIKELY((compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)) || compiler->cpool_fill >= CPOOL_SIZE))
! 231: FAIL_IF(push_cpool(compiler));
! 232:
! 233: SLJIT_ASSERT(compiler->cpool_fill < CPOOL_SIZE && (inst & 0xfff) == 0);
! 234: ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
! 235: FAIL_IF(!ptr);
! 236: compiler->size++;
! 237: *ptr = inst | compiler->cpool_fill;
! 238:
! 239: compiler->cpool[compiler->cpool_fill] = literal;
! 240: compiler->cpool_unique[compiler->cpool_fill] = 1;
! 241: compiler->cpool_fill++;
! 242: if (compiler->cpool_diff == CONST_POOL_EMPTY)
! 243: compiler->cpool_diff = compiler->size;
! 244: return SLJIT_SUCCESS;
! 245: }
! 246:
! 247: static SLJIT_INLINE int prepare_blx(struct sljit_compiler *compiler)
! 248: {
! 249: /* Place for at least two instruction (doesn't matter whether the first has a literal). */
! 250: if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4088)))
! 251: return push_cpool(compiler);
! 252: return SLJIT_SUCCESS;
! 253: }
! 254:
! 255: static SLJIT_INLINE int emit_blx(struct sljit_compiler *compiler)
! 256: {
! 257: /* Must follow tightly the previous instruction (to be able to convert it to bl instruction). */
! 258: SLJIT_ASSERT(compiler->cpool_diff == CONST_POOL_EMPTY || compiler->size - compiler->cpool_diff < MAX_DIFFERENCE(4092));
! 259: return push_inst(compiler, BLX | RM(TMP_REG1));
! 260: }
! 261:
! 262: static sljit_uw patch_pc_relative_loads(sljit_uw *last_pc_patch, sljit_uw *code_ptr, sljit_uw* const_pool, sljit_uw cpool_size)
! 263: {
! 264: sljit_uw diff;
! 265: sljit_uw ind;
! 266: sljit_uw counter = 0;
! 267: sljit_uw* clear_const_pool = const_pool;
! 268: sljit_uw* clear_const_pool_end = const_pool + cpool_size;
! 269:
! 270: SLJIT_ASSERT(const_pool - code_ptr <= CONST_POOL_ALIGNMENT);
! 271: /* Set unused flag for all literals in the constant pool.
! 272: I.e.: unused literals can belong to branches, which can be encoded as B or BL.
! 273: We can "compress" the constant pool by discarding these literals. */
! 274: while (clear_const_pool < clear_const_pool_end)
! 275: *clear_const_pool++ = (sljit_uw)(-1);
! 276:
! 277: while (last_pc_patch < code_ptr) {
! 278: /* Data transfer instruction with Rn == r15. */
! 279: if ((*last_pc_patch & 0x0c0f0000) == 0x040f0000) {
! 280: diff = const_pool - last_pc_patch;
! 281: ind = (*last_pc_patch) & 0xfff;
! 282:
! 283: /* Must be a load instruction with immediate offset. */
! 284: SLJIT_ASSERT(ind < cpool_size && !(*last_pc_patch & (1 << 25)) && (*last_pc_patch & (1 << 20)));
! 285: if ((int)const_pool[ind] < 0) {
! 286: const_pool[ind] = counter;
! 287: ind = counter;
! 288: counter++;
! 289: }
! 290: else
! 291: ind = const_pool[ind];
! 292:
! 293: SLJIT_ASSERT(diff >= 1);
! 294: if (diff >= 2 || ind > 0) {
! 295: diff = (diff + ind - 2) << 2;
! 296: SLJIT_ASSERT(diff <= 0xfff);
! 297: *last_pc_patch = (*last_pc_patch & ~0xfff) | diff;
! 298: }
! 299: else
! 300: *last_pc_patch = (*last_pc_patch & ~(0xfff | (1 << 23))) | 0x004;
! 301: }
! 302: last_pc_patch++;
! 303: }
! 304: return counter;
! 305: }
! 306:
! 307: /* In some rare ocasions we may need future patches. The probability is close to 0 in practice. */
! 308: struct future_patch {
! 309: struct future_patch* next;
! 310: int index;
! 311: int value;
! 312: };
! 313:
! 314: static SLJIT_INLINE int resolve_const_pool_index(struct future_patch **first_patch, sljit_uw cpool_current_index, sljit_uw *cpool_start_address, sljit_uw *buf_ptr)
! 315: {
! 316: int value;
! 317: struct future_patch *curr_patch, *prev_patch;
! 318:
! 319: /* Using the values generated by patch_pc_relative_loads. */
! 320: if (!*first_patch)
! 321: value = (int)cpool_start_address[cpool_current_index];
! 322: else {
! 323: curr_patch = *first_patch;
! 324: prev_patch = 0;
! 325: while (1) {
! 326: if (!curr_patch) {
! 327: value = (int)cpool_start_address[cpool_current_index];
! 328: break;
! 329: }
! 330: if ((sljit_uw)curr_patch->index == cpool_current_index) {
! 331: value = curr_patch->value;
! 332: if (prev_patch)
! 333: prev_patch->next = curr_patch->next;
! 334: else
! 335: *first_patch = curr_patch->next;
! 336: SLJIT_FREE(curr_patch);
! 337: break;
! 338: }
! 339: prev_patch = curr_patch;
! 340: curr_patch = curr_patch->next;
! 341: }
! 342: }
! 343:
! 344: if (value >= 0) {
! 345: if ((sljit_uw)value > cpool_current_index) {
! 346: curr_patch = (struct future_patch*)SLJIT_MALLOC(sizeof(struct future_patch));
! 347: if (!curr_patch) {
! 348: while (*first_patch) {
! 349: curr_patch = *first_patch;
! 350: *first_patch = (*first_patch)->next;
! 351: SLJIT_FREE(curr_patch);
! 352: }
! 353: return SLJIT_ERR_ALLOC_FAILED;
! 354: }
! 355: curr_patch->next = *first_patch;
! 356: curr_patch->index = value;
! 357: curr_patch->value = cpool_start_address[value];
! 358: *first_patch = curr_patch;
! 359: }
! 360: cpool_start_address[value] = *buf_ptr;
! 361: }
! 362: return SLJIT_SUCCESS;
! 363: }
! 364:
! 365: #else
! 366:
! 367: static int push_inst(struct sljit_compiler *compiler, sljit_uw inst)
! 368: {
! 369: sljit_uw* ptr;
! 370:
! 371: ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
! 372: FAIL_IF(!ptr);
! 373: compiler->size++;
! 374: *ptr = inst;
! 375: return SLJIT_SUCCESS;
! 376: }
! 377:
! 378: static SLJIT_INLINE int emit_imm(struct sljit_compiler *compiler, int reg, sljit_w imm)
! 379: {
! 380: FAIL_IF(push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff)));
! 381: return push_inst(compiler, MOVT | RD(reg) | ((imm >> 12) & 0xf0000) | ((imm >> 16) & 0xfff));
! 382: }
! 383:
! 384: #endif
! 385:
! 386: static SLJIT_INLINE int detect_jump_type(struct sljit_jump *jump, sljit_uw *code_ptr, sljit_uw *code)
! 387: {
! 388: sljit_w diff;
! 389:
! 390: if (jump->flags & SLJIT_REWRITABLE_JUMP)
! 391: return 0;
! 392:
! 393: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 394: if (jump->flags & IS_BL)
! 395: code_ptr--;
! 396:
! 397: if (jump->flags & JUMP_ADDR)
! 398: diff = ((sljit_w)jump->u.target - (sljit_w)(code_ptr + 2));
! 399: else {
! 400: SLJIT_ASSERT(jump->flags & JUMP_LABEL);
! 401: diff = ((sljit_w)(code + jump->u.label->size) - (sljit_w)(code_ptr + 2));
! 402: }
! 403:
! 404: /* Branch to Thumb code has not been optimized yet. */
! 405: if (diff & 0x3)
! 406: return 0;
! 407:
! 408: diff >>= 2;
! 409: if (jump->flags & IS_BL) {
! 410: if (diff <= 0x01ffffff && diff >= -0x02000000) {
! 411: *code_ptr = (BL - CONDITIONAL) | (*(code_ptr + 1) & COND_MASK);
! 412: jump->flags |= PATCH_B;
! 413: return 1;
! 414: }
! 415: }
! 416: else {
! 417: if (diff <= 0x01ffffff && diff >= -0x02000000) {
! 418: *code_ptr = (B - CONDITIONAL) | (*code_ptr & COND_MASK);
! 419: jump->flags |= PATCH_B;
! 420: }
! 421: }
! 422: #else
! 423: if (jump->flags & JUMP_ADDR)
! 424: diff = ((sljit_w)jump->u.target - (sljit_w)code_ptr);
! 425: else {
! 426: SLJIT_ASSERT(jump->flags & JUMP_LABEL);
! 427: diff = ((sljit_w)(code + jump->u.label->size) - (sljit_w)code_ptr);
! 428: }
! 429:
! 430: /* Branch to Thumb code has not been optimized yet. */
! 431: if (diff & 0x3)
! 432: return 0;
! 433:
! 434: diff >>= 2;
! 435: if (diff <= 0x01ffffff && diff >= -0x02000000) {
! 436: code_ptr -= 2;
! 437: *code_ptr = ((jump->flags & IS_BL) ? (BL - CONDITIONAL) : (B - CONDITIONAL)) | (code_ptr[2] & COND_MASK);
! 438: jump->flags |= PATCH_B;
! 439: return 1;
! 440: }
! 441: #endif
! 442: return 0;
! 443: }
! 444:
! 445: static SLJIT_INLINE void inline_set_jump_addr(sljit_uw addr, sljit_uw new_addr, int flush)
! 446: {
! 447: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 448: sljit_uw *ptr = (sljit_uw*)addr;
! 449: sljit_uw *inst = (sljit_uw*)ptr[0];
! 450: sljit_uw mov_pc = ptr[1];
! 451: int bl = (mov_pc & 0x0000f000) != RD(TMP_PC);
! 452: sljit_w diff = (sljit_w)(((sljit_w)new_addr - (sljit_w)(inst + 2)) >> 2);
! 453:
! 454: if (diff <= 0x7fffff && diff >= -0x800000) {
! 455: /* Turn to branch. */
! 456: if (!bl) {
! 457: inst[0] = (mov_pc & COND_MASK) | (B - CONDITIONAL) | (diff & 0xffffff);
! 458: if (flush) {
! 459: SLJIT_CACHE_FLUSH(inst, inst + 1);
! 460: }
! 461: } else {
! 462: inst[0] = (mov_pc & COND_MASK) | (BL - CONDITIONAL) | (diff & 0xffffff);
! 463: inst[1] = NOP;
! 464: if (flush) {
! 465: SLJIT_CACHE_FLUSH(inst, inst + 2);
! 466: }
! 467: }
! 468: } else {
! 469: /* Get the position of the constant. */
! 470: if (mov_pc & (1 << 23))
! 471: ptr = inst + ((mov_pc & 0xfff) >> 2) + 2;
! 472: else
! 473: ptr = inst + 1;
! 474:
! 475: if (*inst != mov_pc) {
! 476: inst[0] = mov_pc;
! 477: if (!bl) {
! 478: if (flush) {
! 479: SLJIT_CACHE_FLUSH(inst, inst + 1);
! 480: }
! 481: } else {
! 482: inst[1] = BLX | RM(TMP_REG1);
! 483: if (flush) {
! 484: SLJIT_CACHE_FLUSH(inst, inst + 2);
! 485: }
! 486: }
! 487: }
! 488: *ptr = new_addr;
! 489: }
! 490: #else
! 491: sljit_uw *inst = (sljit_uw*)addr;
! 492: SLJIT_ASSERT((inst[0] & 0xfff00000) == MOVW && (inst[1] & 0xfff00000) == MOVT);
! 493: inst[0] = MOVW | (inst[0] & 0xf000) | ((new_addr << 4) & 0xf0000) | (new_addr & 0xfff);
! 494: inst[1] = MOVT | (inst[1] & 0xf000) | ((new_addr >> 12) & 0xf0000) | ((new_addr >> 16) & 0xfff);
! 495: if (flush) {
! 496: SLJIT_CACHE_FLUSH(inst, inst + 2);
! 497: }
! 498: #endif
! 499: }
! 500:
! 501: static sljit_uw get_immediate(sljit_uw imm);
! 502:
! 503: static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_w new_constant, int flush)
! 504: {
! 505: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 506: sljit_uw *ptr = (sljit_uw*)addr;
! 507: sljit_uw *inst = (sljit_uw*)ptr[0];
! 508: sljit_uw ldr_literal = ptr[1];
! 509: sljit_uw src2;
! 510:
! 511: src2 = get_immediate(new_constant);
! 512: if (src2) {
! 513: *inst = 0xe3a00000 | (ldr_literal & 0xf000) | src2;
! 514: if (flush) {
! 515: SLJIT_CACHE_FLUSH(inst, inst + 1);
! 516: }
! 517: return;
! 518: }
! 519:
! 520: src2 = get_immediate(~new_constant);
! 521: if (src2) {
! 522: *inst = 0xe3e00000 | (ldr_literal & 0xf000) | src2;
! 523: if (flush) {
! 524: SLJIT_CACHE_FLUSH(inst, inst + 1);
! 525: }
! 526: return;
! 527: }
! 528:
! 529: if (ldr_literal & (1 << 23))
! 530: ptr = inst + ((ldr_literal & 0xfff) >> 2) + 2;
! 531: else
! 532: ptr = inst + 1;
! 533:
! 534: if (*inst != ldr_literal) {
! 535: *inst = ldr_literal;
! 536: if (flush) {
! 537: SLJIT_CACHE_FLUSH(inst, inst + 1);
! 538: }
! 539: }
! 540: *ptr = new_constant;
! 541: #else
! 542: sljit_uw *inst = (sljit_uw*)addr;
! 543: SLJIT_ASSERT((inst[0] & 0xfff00000) == MOVW && (inst[1] & 0xfff00000) == MOVT);
! 544: inst[0] = MOVW | (inst[0] & 0xf000) | ((new_constant << 4) & 0xf0000) | (new_constant & 0xfff);
! 545: inst[1] = MOVT | (inst[1] & 0xf000) | ((new_constant >> 12) & 0xf0000) | ((new_constant >> 16) & 0xfff);
! 546: if (flush) {
! 547: SLJIT_CACHE_FLUSH(inst, inst + 2);
! 548: }
! 549: #endif
! 550: }
! 551:
! 552: SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
! 553: {
! 554: struct sljit_memory_fragment *buf;
! 555: sljit_uw *code;
! 556: sljit_uw *code_ptr;
! 557: sljit_uw *buf_ptr;
! 558: sljit_uw *buf_end;
! 559: sljit_uw size;
! 560: sljit_uw word_count;
! 561: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 562: sljit_uw cpool_size;
! 563: sljit_uw cpool_skip_alignment;
! 564: sljit_uw cpool_current_index;
! 565: sljit_uw *cpool_start_address;
! 566: sljit_uw *last_pc_patch;
! 567: struct future_patch *first_patch;
! 568: #endif
! 569:
! 570: struct sljit_label *label;
! 571: struct sljit_jump *jump;
! 572: struct sljit_const *const_;
! 573:
! 574: CHECK_ERROR_PTR();
! 575: check_sljit_generate_code(compiler);
! 576: reverse_buf(compiler);
! 577:
! 578: /* Second code generation pass. */
! 579: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 580: size = compiler->size + (compiler->patches << 1);
! 581: if (compiler->cpool_fill > 0)
! 582: size += compiler->cpool_fill + CONST_POOL_ALIGNMENT - 1;
! 583: #else
! 584: size = compiler->size;
! 585: #endif
! 586: code = (sljit_uw*)SLJIT_MALLOC_EXEC(size * sizeof(sljit_uw));
! 587: PTR_FAIL_WITH_EXEC_IF(code);
! 588: buf = compiler->buf;
! 589:
! 590: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 591: cpool_size = 0;
! 592: cpool_skip_alignment = 0;
! 593: cpool_current_index = 0;
! 594: cpool_start_address = NULL;
! 595: first_patch = NULL;
! 596: last_pc_patch = code;
! 597: #endif
! 598:
! 599: code_ptr = code;
! 600: word_count = 0;
! 601:
! 602: label = compiler->labels;
! 603: jump = compiler->jumps;
! 604: const_ = compiler->consts;
! 605:
! 606: if (label && label->size == 0) {
! 607: label->addr = (sljit_uw)code;
! 608: label->size = 0;
! 609: label = label->next;
! 610: }
! 611:
! 612: do {
! 613: buf_ptr = (sljit_uw*)buf->memory;
! 614: buf_end = buf_ptr + (buf->used_size >> 2);
! 615: do {
! 616: word_count++;
! 617: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 618: if (cpool_size > 0) {
! 619: if (cpool_skip_alignment > 0) {
! 620: buf_ptr++;
! 621: cpool_skip_alignment--;
! 622: }
! 623: else {
! 624: if (SLJIT_UNLIKELY(resolve_const_pool_index(&first_patch, cpool_current_index, cpool_start_address, buf_ptr))) {
! 625: SLJIT_FREE_EXEC(code);
! 626: compiler->error = SLJIT_ERR_ALLOC_FAILED;
! 627: return NULL;
! 628: }
! 629: buf_ptr++;
! 630: if (++cpool_current_index >= cpool_size) {
! 631: SLJIT_ASSERT(!first_patch);
! 632: cpool_size = 0;
! 633: if (label && label->size == word_count) {
! 634: /* Points after the current instruction. */
! 635: label->addr = (sljit_uw)code_ptr;
! 636: label->size = code_ptr - code;
! 637: label = label->next;
! 638: }
! 639: }
! 640: }
! 641: }
! 642: else if ((*buf_ptr & 0xff000000) != PUSH_POOL) {
! 643: #endif
! 644: *code_ptr = *buf_ptr++;
! 645: /* These structures are ordered by their address. */
! 646: SLJIT_ASSERT(!label || label->size >= word_count);
! 647: SLJIT_ASSERT(!jump || jump->addr >= word_count);
! 648: SLJIT_ASSERT(!const_ || const_->addr >= word_count);
! 649: if (jump && jump->addr == word_count) {
! 650: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 651: if (detect_jump_type(jump, code_ptr, code))
! 652: code_ptr--;
! 653: jump->addr = (sljit_uw)code_ptr;
! 654: #else
! 655: jump->addr = (sljit_uw)(code_ptr - 2);
! 656: if (detect_jump_type(jump, code_ptr, code))
! 657: code_ptr -= 2;
! 658: #endif
! 659: jump = jump->next;
! 660: }
! 661: if (label && label->size == word_count) {
! 662: /* code_ptr can be affected above. */
! 663: label->addr = (sljit_uw)(code_ptr + 1);
! 664: label->size = (code_ptr + 1) - code;
! 665: label = label->next;
! 666: }
! 667: if (const_ && const_->addr == word_count) {
! 668: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 669: const_->addr = (sljit_uw)code_ptr;
! 670: #else
! 671: const_->addr = (sljit_uw)(code_ptr - 1);
! 672: #endif
! 673: const_ = const_->next;
! 674: }
! 675: code_ptr++;
! 676: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 677: }
! 678: else {
! 679: /* Fortunately, no need to shift. */
! 680: cpool_size = *buf_ptr++ & ~PUSH_POOL;
! 681: SLJIT_ASSERT(cpool_size > 0);
! 682: cpool_start_address = ALIGN_INSTRUCTION(code_ptr + 1);
! 683: cpool_current_index = patch_pc_relative_loads(last_pc_patch, code_ptr, cpool_start_address, cpool_size);
! 684: if (cpool_current_index > 0) {
! 685: /* Unconditional branch. */
! 686: *code_ptr = B | (((cpool_start_address - code_ptr) + cpool_current_index - 2) & ~PUSH_POOL);
! 687: code_ptr = cpool_start_address + cpool_current_index;
! 688: }
! 689: cpool_skip_alignment = CONST_POOL_ALIGNMENT - 1;
! 690: cpool_current_index = 0;
! 691: last_pc_patch = code_ptr;
! 692: }
! 693: #endif
! 694: } while (buf_ptr < buf_end);
! 695: buf = buf->next;
! 696: } while (buf);
! 697:
! 698: SLJIT_ASSERT(!label);
! 699: SLJIT_ASSERT(!jump);
! 700: SLJIT_ASSERT(!const_);
! 701:
! 702: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 703: SLJIT_ASSERT(cpool_size == 0);
! 704: if (compiler->cpool_fill > 0) {
! 705: cpool_start_address = ALIGN_INSTRUCTION(code_ptr);
! 706: cpool_current_index = patch_pc_relative_loads(last_pc_patch, code_ptr, cpool_start_address, compiler->cpool_fill);
! 707: if (cpool_current_index > 0)
! 708: code_ptr = cpool_start_address + cpool_current_index;
! 709:
! 710: buf_ptr = compiler->cpool;
! 711: buf_end = buf_ptr + compiler->cpool_fill;
! 712: cpool_current_index = 0;
! 713: while (buf_ptr < buf_end) {
! 714: if (SLJIT_UNLIKELY(resolve_const_pool_index(&first_patch, cpool_current_index, cpool_start_address, buf_ptr))) {
! 715: SLJIT_FREE_EXEC(code);
! 716: compiler->error = SLJIT_ERR_ALLOC_FAILED;
! 717: return NULL;
! 718: }
! 719: buf_ptr++;
! 720: cpool_current_index++;
! 721: }
! 722: SLJIT_ASSERT(!first_patch);
! 723: }
! 724: #endif
! 725:
! 726: jump = compiler->jumps;
! 727: while (jump) {
! 728: buf_ptr = (sljit_uw*)jump->addr;
! 729:
! 730: if (jump->flags & PATCH_B) {
! 731: if (!(jump->flags & JUMP_ADDR)) {
! 732: SLJIT_ASSERT(jump->flags & JUMP_LABEL);
! 733: SLJIT_ASSERT(((sljit_w)jump->u.label->addr - (sljit_w)(buf_ptr + 2)) <= 0x01ffffff && ((sljit_w)jump->u.label->addr - (sljit_w)(buf_ptr + 2)) >= -0x02000000);
! 734: *buf_ptr |= (((sljit_w)jump->u.label->addr - (sljit_w)(buf_ptr + 2)) >> 2) & 0x00ffffff;
! 735: }
! 736: else {
! 737: SLJIT_ASSERT(((sljit_w)jump->u.target - (sljit_w)(buf_ptr + 2)) <= 0x01ffffff && ((sljit_w)jump->u.target - (sljit_w)(buf_ptr + 2)) >= -0x02000000);
! 738: *buf_ptr |= (((sljit_w)jump->u.target - (sljit_w)(buf_ptr + 2)) >> 2) & 0x00ffffff;
! 739: }
! 740: }
! 741: else if (jump->flags & SLJIT_REWRITABLE_JUMP) {
! 742: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 743: jump->addr = (sljit_uw)code_ptr;
! 744: code_ptr[0] = (sljit_uw)buf_ptr;
! 745: code_ptr[1] = *buf_ptr;
! 746: inline_set_jump_addr((sljit_uw)code_ptr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
! 747: code_ptr += 2;
! 748: #else
! 749: inline_set_jump_addr((sljit_uw)buf_ptr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
! 750: #endif
! 751: }
! 752: else {
! 753: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 754: if (jump->flags & IS_BL)
! 755: buf_ptr--;
! 756: if (*buf_ptr & (1 << 23))
! 757: buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2;
! 758: else
! 759: buf_ptr += 1;
! 760: *buf_ptr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
! 761: #else
! 762: inline_set_jump_addr((sljit_uw)buf_ptr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
! 763: #endif
! 764: }
! 765: jump = jump->next;
! 766: }
! 767:
! 768: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 769: const_ = compiler->consts;
! 770: while (const_) {
! 771: buf_ptr = (sljit_uw*)const_->addr;
! 772: const_->addr = (sljit_uw)code_ptr;
! 773:
! 774: code_ptr[0] = (sljit_uw)buf_ptr;
! 775: code_ptr[1] = *buf_ptr;
! 776: if (*buf_ptr & (1 << 23))
! 777: buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2;
! 778: else
! 779: buf_ptr += 1;
! 780: /* Set the value again (can be a simple constant). */
! 781: inline_set_const((sljit_uw)code_ptr, *buf_ptr, 0);
! 782: code_ptr += 2;
! 783:
! 784: const_ = const_->next;
! 785: }
! 786: #endif
! 787:
! 788: SLJIT_ASSERT(code_ptr - code <= (int)size);
! 789:
! 790: SLJIT_CACHE_FLUSH(code, code_ptr);
! 791: compiler->error = SLJIT_ERR_COMPILED;
! 792: compiler->executable_size = size * sizeof(sljit_uw);
! 793: return code;
! 794: }
! 795:
! 796: /* emit_op inp_flags.
! 797: WRITE_BACK must be the first, since it is a flag. */
! 798: #define WRITE_BACK 0x01
! 799: #define ALLOW_IMM 0x02
! 800: #define ALLOW_INV_IMM 0x04
! 801: #define ALLOW_ANY_IMM (ALLOW_IMM | ALLOW_INV_IMM)
! 802: #define ARG_TEST 0x08
! 803:
! 804: /* Creates an index in data_transfer_insts array. */
! 805: #define WORD_DATA 0x00
! 806: #define BYTE_DATA 0x10
! 807: #define HALF_DATA 0x20
! 808: #define SIGNED_DATA 0x40
! 809: #define LOAD_DATA 0x80
! 810:
! 811: #define EMIT_INSTRUCTION(inst) \
! 812: FAIL_IF(push_inst(compiler, (inst)))
! 813:
! 814: /* Condition: AL. */
! 815: #define EMIT_DATA_PROCESS_INS(opcode, set_flags, dst, src1, src2) \
! 816: (0xe0000000 | ((opcode) << 21) | (set_flags) | RD(dst) | RN(src1) | (src2))
! 817:
! 818: static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags,
! 819: int dst, sljit_w dstw,
! 820: int src1, sljit_w src1w,
! 821: int src2, sljit_w src2w);
! 822:
! 823: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size)
! 824: {
! 825: int size;
! 826: sljit_uw push;
! 827:
! 828: CHECK_ERROR();
! 829: check_sljit_emit_enter(compiler, args, temporaries, saveds, local_size);
! 830:
! 831: compiler->temporaries = temporaries;
! 832: compiler->saveds = saveds;
! 833:
! 834: /* Push saved registers, temporary registers
! 835: stmdb sp!, {..., lr} */
! 836: push = PUSH | (1 << 14);
! 837: if (temporaries >= 5)
! 838: push |= 1 << 11;
! 839: if (temporaries >= 4)
! 840: push |= 1 << 10;
! 841: if (saveds >= 5)
! 842: push |= 1 << 8;
! 843: if (saveds >= 4)
! 844: push |= 1 << 7;
! 845: if (saveds >= 3)
! 846: push |= 1 << 6;
! 847: if (saveds >= 2)
! 848: push |= 1 << 5;
! 849: if (saveds >= 1)
! 850: push |= 1 << 4;
! 851: EMIT_INSTRUCTION(push);
! 852:
! 853: /* Stack must be aligned to 8 bytes: */
! 854: size = (1 + saveds) * sizeof(sljit_uw);
! 855: if (temporaries >= 4)
! 856: size += (temporaries - 3) * sizeof(sljit_uw);
! 857: local_size += size;
! 858: local_size = (local_size + 7) & ~7;
! 859: local_size -= size;
! 860: compiler->local_size = local_size;
! 861: if (local_size > 0)
! 862: FAIL_IF(emit_op(compiler, SLJIT_SUB, ALLOW_IMM, SLJIT_LOCALS_REG, 0, SLJIT_LOCALS_REG, 0, SLJIT_IMM, local_size));
! 863:
! 864: if (args >= 1)
! 865: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, SLJIT_SAVED_REG1, SLJIT_UNUSED, RM(SLJIT_TEMPORARY_REG1)));
! 866: if (args >= 2)
! 867: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, SLJIT_SAVED_REG2, SLJIT_UNUSED, RM(SLJIT_TEMPORARY_REG2)));
! 868: if (args >= 3)
! 869: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, SLJIT_SAVED_REG3, SLJIT_UNUSED, RM(SLJIT_TEMPORARY_REG3)));
! 870:
! 871: return SLJIT_SUCCESS;
! 872: }
! 873:
! 874: SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size)
! 875: {
! 876: int size;
! 877:
! 878: CHECK_ERROR_VOID();
! 879: check_sljit_set_context(compiler, args, temporaries, saveds, local_size);
! 880:
! 881: compiler->temporaries = temporaries;
! 882: compiler->saveds = saveds;
! 883:
! 884: size = (1 + saveds) * sizeof(sljit_uw);
! 885: if (temporaries >= 4)
! 886: size += (temporaries - 3) * sizeof(sljit_uw);
! 887: local_size += size;
! 888: local_size = (local_size + 7) & ~7;
! 889: local_size -= size;
! 890: compiler->local_size = local_size;
! 891: }
! 892:
! 893: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw)
! 894: {
! 895: sljit_uw pop;
! 896:
! 897: CHECK_ERROR();
! 898: check_sljit_emit_return(compiler, op, src, srcw);
! 899:
! 900: FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
! 901:
! 902: if (compiler->local_size > 0)
! 903: FAIL_IF(emit_op(compiler, SLJIT_ADD, ALLOW_IMM, SLJIT_LOCALS_REG, 0, SLJIT_LOCALS_REG, 0, SLJIT_IMM, compiler->local_size));
! 904:
! 905: pop = POP | (1 << 15);
! 906: /* Push saved registers, temporary registers
! 907: ldmia sp!, {..., pc} */
! 908: if (compiler->temporaries >= 5)
! 909: pop |= 1 << 11;
! 910: if (compiler->temporaries >= 4)
! 911: pop |= 1 << 10;
! 912: if (compiler->saveds >= 5)
! 913: pop |= 1 << 8;
! 914: if (compiler->saveds >= 4)
! 915: pop |= 1 << 7;
! 916: if (compiler->saveds >= 3)
! 917: pop |= 1 << 6;
! 918: if (compiler->saveds >= 2)
! 919: pop |= 1 << 5;
! 920: if (compiler->saveds >= 1)
! 921: pop |= 1 << 4;
! 922:
! 923: return push_inst(compiler, pop);
! 924: }
! 925:
! 926: /* --------------------------------------------------------------------- */
! 927: /* Operators */
! 928: /* --------------------------------------------------------------------- */
! 929:
! 930: /* s/l - store/load (1 bit)
! 931: u/s - signed/unsigned (1 bit)
! 932: w/b/h/N - word/byte/half/NOT allowed (2 bit)
! 933: It contans 16 items, but not all are different. */
! 934:
! 935: static sljit_w data_transfer_insts[16] = {
! 936: /* s u w */ 0xe5000000 /* str */,
! 937: /* s u b */ 0xe5400000 /* strb */,
! 938: /* s u h */ 0xe10000b0 /* strh */,
! 939: /* s u N */ 0x00000000 /* not allowed */,
! 940: /* s s w */ 0xe5000000 /* str */,
! 941: /* s s b */ 0xe5400000 /* strb */,
! 942: /* s s h */ 0xe10000b0 /* strh */,
! 943: /* s s N */ 0x00000000 /* not allowed */,
! 944:
! 945: /* l u w */ 0xe5100000 /* ldr */,
! 946: /* l u b */ 0xe5500000 /* ldrb */,
! 947: /* l u h */ 0xe11000b0 /* ldrh */,
! 948: /* l u N */ 0x00000000 /* not allowed */,
! 949: /* l s w */ 0xe5100000 /* ldr */,
! 950: /* l s b */ 0xe11000d0 /* ldrsb */,
! 951: /* l s h */ 0xe11000f0 /* ldrsh */,
! 952: /* l s N */ 0x00000000 /* not allowed */,
! 953: };
! 954:
! 955: #define EMIT_DATA_TRANSFER(type, add, wb, target, base1, base2) \
! 956: (data_transfer_insts[(type) >> 4] | ((add) << 23) | ((wb) << 21) | (reg_map[target] << 12) | (reg_map[base1] << 16) | (base2))
! 957: /* Normal ldr/str instruction.
! 958: Type2: ldrsb, ldrh, ldrsh */
! 959: #define IS_TYPE1_TRANSFER(type) \
! 960: (data_transfer_insts[(type) >> 4] & 0x04000000)
! 961: #define TYPE2_TRANSFER_IMM(imm) \
! 962: (((imm) & 0xf) | (((imm) & 0xf0) << 4) | (1 << 22))
! 963:
! 964: /* flags: */
! 965: /* Arguments are swapped. */
! 966: #define ARGS_SWAPPED 0x01
! 967: /* Inverted immediate. */
! 968: #define INV_IMM 0x02
! 969: /* Source and destination is register. */
! 970: #define REG_DEST 0x04
! 971: #define REG_SOURCE 0x08
! 972: /* One instruction is enough. */
! 973: #define FAST_DEST 0x10
! 974: /* Multiple instructions are required. */
! 975: #define SLOW_DEST 0x20
! 976: /* SET_FLAGS must be (1 << 20) as it is also the value of S bit (can be used for optimization). */
! 977: #define SET_FLAGS (1 << 20)
! 978: /* dst: reg
! 979: src1: reg
! 980: src2: reg or imm (if allowed)
! 981: SRC2_IMM must be (1 << 25) as it is also the value of I bit (can be used for optimization). */
! 982: #define SRC2_IMM (1 << 25)
! 983:
! 984: #define EMIT_DATA_PROCESS_INS_AND_RETURN(opcode) \
! 985: return push_inst(compiler, EMIT_DATA_PROCESS_INS(opcode, flags & SET_FLAGS, dst, src1, (src2 & SRC2_IMM) ? src2 : RM(src2)))
! 986:
! 987: #define EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(opcode, dst, src1, src2) \
! 988: return push_inst(compiler, EMIT_DATA_PROCESS_INS(opcode, flags & SET_FLAGS, dst, src1, src2))
! 989:
! 990: #define EMIT_SHIFT_INS_AND_RETURN(opcode) \
! 991: SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM)); \
! 992: if (compiler->shift_imm != 0x20) { \
! 993: SLJIT_ASSERT(src1 == TMP_REG1); \
! 994: SLJIT_ASSERT(!(flags & ARGS_SWAPPED)); \
! 995: if (compiler->shift_imm != 0) \
! 996: return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, (compiler->shift_imm << 7) | (opcode << 5) | reg_map[src2])); \
! 997: return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, reg_map[src2])); \
! 998: } \
! 999: return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, (reg_map[(flags & ARGS_SWAPPED) ? src1 : src2] << 8) | (opcode << 5) | 0x10 | ((flags & ARGS_SWAPPED) ? reg_map[src2] : reg_map[src1])));
! 1000:
! 1001: static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, int flags,
! 1002: int dst, int src1, int src2)
! 1003: {
! 1004: sljit_w mul_inst;
! 1005:
! 1006: switch (GET_OPCODE(op)) {
! 1007: case SLJIT_ADD:
! 1008: SLJIT_ASSERT(!(flags & INV_IMM));
! 1009: EMIT_DATA_PROCESS_INS_AND_RETURN(ADD_DP);
! 1010:
! 1011: case SLJIT_ADDC:
! 1012: SLJIT_ASSERT(!(flags & INV_IMM));
! 1013: EMIT_DATA_PROCESS_INS_AND_RETURN(ADC_DP);
! 1014:
! 1015: case SLJIT_SUB:
! 1016: SLJIT_ASSERT(!(flags & INV_IMM));
! 1017: if (!(flags & ARGS_SWAPPED))
! 1018: EMIT_DATA_PROCESS_INS_AND_RETURN(SUB_DP);
! 1019: EMIT_DATA_PROCESS_INS_AND_RETURN(RSB_DP);
! 1020:
! 1021: case SLJIT_SUBC:
! 1022: SLJIT_ASSERT(!(flags & INV_IMM));
! 1023: if (!(flags & ARGS_SWAPPED))
! 1024: EMIT_DATA_PROCESS_INS_AND_RETURN(SBC_DP);
! 1025: EMIT_DATA_PROCESS_INS_AND_RETURN(RSC_DP);
! 1026:
! 1027: case SLJIT_MUL:
! 1028: SLJIT_ASSERT(!(flags & INV_IMM));
! 1029: SLJIT_ASSERT(!(src2 & SRC2_IMM));
! 1030: if (SLJIT_UNLIKELY(op & SLJIT_SET_O))
! 1031: mul_inst = SMULL | (reg_map[TMP_REG3] << 16) | (reg_map[dst] << 12);
! 1032: else
! 1033: mul_inst = MUL | (reg_map[dst] << 16);
! 1034:
! 1035: if (dst != src2)
! 1036: FAIL_IF(push_inst(compiler, mul_inst | (reg_map[src1] << 8) | reg_map[src2]));
! 1037: else if (dst != src1)
! 1038: FAIL_IF(push_inst(compiler, mul_inst | (reg_map[src2] << 8) | reg_map[src1]));
! 1039: else {
! 1040: /* Rm and Rd must not be the same register. */
! 1041: SLJIT_ASSERT(dst != TMP_REG1);
! 1042: FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG1, SLJIT_UNUSED, reg_map[src2])));
! 1043: FAIL_IF(push_inst(compiler, mul_inst | (reg_map[src2] << 8) | reg_map[TMP_REG1]));
! 1044: }
! 1045:
! 1046: if (!(op & SLJIT_SET_O))
! 1047: return SLJIT_SUCCESS;
! 1048:
! 1049: /* We need to use TMP_REG3. */
! 1050: compiler->cache_arg = 0;
! 1051: compiler->cache_argw = 0;
! 1052: /* cmp TMP_REG2, dst asr #31. */
! 1053: return push_inst(compiler, EMIT_DATA_PROCESS_INS(CMP_DP, SET_FLAGS, SLJIT_UNUSED, TMP_REG3, RM(dst) | 0xfc0));
! 1054:
! 1055: case SLJIT_AND:
! 1056: if (!(flags & INV_IMM))
! 1057: EMIT_DATA_PROCESS_INS_AND_RETURN(AND_DP);
! 1058: EMIT_DATA_PROCESS_INS_AND_RETURN(BIC_DP);
! 1059:
! 1060: case SLJIT_OR:
! 1061: SLJIT_ASSERT(!(flags & INV_IMM));
! 1062: EMIT_DATA_PROCESS_INS_AND_RETURN(ORR_DP);
! 1063:
! 1064: case SLJIT_XOR:
! 1065: SLJIT_ASSERT(!(flags & INV_IMM));
! 1066: EMIT_DATA_PROCESS_INS_AND_RETURN(EOR_DP);
! 1067:
! 1068: case SLJIT_SHL:
! 1069: EMIT_SHIFT_INS_AND_RETURN(0);
! 1070:
! 1071: case SLJIT_LSHR:
! 1072: EMIT_SHIFT_INS_AND_RETURN(1);
! 1073:
! 1074: case SLJIT_ASHR:
! 1075: EMIT_SHIFT_INS_AND_RETURN(2);
! 1076:
! 1077: case SLJIT_MOV:
! 1078: SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
! 1079: if (dst != src2) {
! 1080: if (src2 & SRC2_IMM) {
! 1081: if (flags & INV_IMM)
! 1082: EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2);
! 1083: EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2);
! 1084: }
! 1085: EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, reg_map[src2]);
! 1086: }
! 1087: return SLJIT_SUCCESS;
! 1088:
! 1089: case SLJIT_MOV_UB:
! 1090: case SLJIT_MOV_SB:
! 1091: SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
! 1092: if ((flags & (REG_DEST | REG_SOURCE)) == (REG_DEST | REG_SOURCE)) {
! 1093: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 1094: if (op == SLJIT_MOV_UB)
! 1095: return push_inst(compiler, EMIT_DATA_PROCESS_INS(AND_DP, 0, dst, src2, SRC2_IMM | 0xff));
! 1096: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (24 << 7) | reg_map[src2]));
! 1097: return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (24 << 7) | (op == SLJIT_MOV_UB ? 0x20 : 0x40) | reg_map[dst]));
! 1098: #else
! 1099: return push_inst(compiler, (op == SLJIT_MOV_UB ? UXTB : SXTB) | RD(dst) | RM(src2));
! 1100: #endif
! 1101: }
! 1102: else if (dst != src2) {
! 1103: SLJIT_ASSERT(src2 & SRC2_IMM);
! 1104: if (flags & INV_IMM)
! 1105: EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2);
! 1106: EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2);
! 1107: }
! 1108: return SLJIT_SUCCESS;
! 1109:
! 1110: case SLJIT_MOV_UH:
! 1111: case SLJIT_MOV_SH:
! 1112: SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
! 1113: if ((flags & (REG_DEST | REG_SOURCE)) == (REG_DEST | REG_SOURCE)) {
! 1114: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 1115: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (16 << 7) | reg_map[src2]));
! 1116: return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (16 << 7) | (op == SLJIT_MOV_UH ? 0x20 : 0x40) | reg_map[dst]));
! 1117: #else
! 1118: return push_inst(compiler, (op == SLJIT_MOV_UH ? UXTH : SXTH) | RD(dst) | RM(src2));
! 1119: #endif
! 1120: }
! 1121: else if (dst != src2) {
! 1122: SLJIT_ASSERT(src2 & SRC2_IMM);
! 1123: if (flags & INV_IMM)
! 1124: EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2);
! 1125: EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2);
! 1126: }
! 1127: return SLJIT_SUCCESS;
! 1128:
! 1129: case SLJIT_NOT:
! 1130: if (src2 & SRC2_IMM) {
! 1131: if (flags & INV_IMM)
! 1132: EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2);
! 1133: EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2);
! 1134: }
! 1135: EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, RM(src2));
! 1136:
! 1137: case SLJIT_CLZ:
! 1138: SLJIT_ASSERT(!(flags & INV_IMM));
! 1139: SLJIT_ASSERT(!(src2 & SRC2_IMM));
! 1140: FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(src2)));
! 1141: if (flags & SET_FLAGS)
! 1142: EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(CMP_DP, SLJIT_UNUSED, dst, SRC2_IMM);
! 1143: return SLJIT_SUCCESS;
! 1144: }
! 1145: SLJIT_ASSERT_STOP();
! 1146: return SLJIT_SUCCESS;
! 1147: }
! 1148:
! 1149: #undef EMIT_DATA_PROCESS_INS_AND_RETURN
! 1150: #undef EMIT_FULL_DATA_PROCESS_INS_AND_RETURN
! 1151: #undef EMIT_SHIFT_INS_AND_RETURN
! 1152:
! 1153: /* Tests whether the immediate can be stored in the 12 bit imm field.
! 1154: Returns with 0 if not possible. */
! 1155: static sljit_uw get_immediate(sljit_uw imm)
! 1156: {
! 1157: int rol;
! 1158:
! 1159: if (imm <= 0xff)
! 1160: return SRC2_IMM | imm;
! 1161:
! 1162: if (!(imm & 0xff000000)) {
! 1163: imm <<= 8;
! 1164: rol = 8;
! 1165: }
! 1166: else {
! 1167: imm = (imm << 24) | (imm >> 8);
! 1168: rol = 0;
! 1169: }
! 1170:
! 1171: if (!(imm & 0xff000000)) {
! 1172: imm <<= 8;
! 1173: rol += 4;
! 1174: }
! 1175:
! 1176: if (!(imm & 0xf0000000)) {
! 1177: imm <<= 4;
! 1178: rol += 2;
! 1179: }
! 1180:
! 1181: if (!(imm & 0xc0000000)) {
! 1182: imm <<= 2;
! 1183: rol += 1;
! 1184: }
! 1185:
! 1186: if (!(imm & 0x00ffffff))
! 1187: return SRC2_IMM | (imm >> 24) | (rol << 8);
! 1188: else
! 1189: return 0;
! 1190: }
! 1191:
! 1192: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 1193: static int generate_int(struct sljit_compiler *compiler, int reg, sljit_uw imm, int positive)
! 1194: {
! 1195: sljit_uw mask;
! 1196: sljit_uw imm1;
! 1197: sljit_uw imm2;
! 1198: int rol;
! 1199:
! 1200: /* Step1: Search a zero byte (8 continous zero bit). */
! 1201: mask = 0xff000000;
! 1202: rol = 8;
! 1203: while(1) {
! 1204: if (!(imm & mask)) {
! 1205: /* Rol imm by rol. */
! 1206: imm = (imm << rol) | (imm >> (32 - rol));
! 1207: /* Calculate arm rol. */
! 1208: rol = 4 + (rol >> 1);
! 1209: break;
! 1210: }
! 1211: rol += 2;
! 1212: mask >>= 2;
! 1213: if (mask & 0x3) {
! 1214: /* rol by 8. */
! 1215: imm = (imm << 8) | (imm >> 24);
! 1216: mask = 0xff00;
! 1217: rol = 24;
! 1218: while (1) {
! 1219: if (!(imm & mask)) {
! 1220: /* Rol imm by rol. */
! 1221: imm = (imm << rol) | (imm >> (32 - rol));
! 1222: /* Calculate arm rol. */
! 1223: rol = (rol >> 1) - 8;
! 1224: break;
! 1225: }
! 1226: rol += 2;
! 1227: mask >>= 2;
! 1228: if (mask & 0x3)
! 1229: return 0;
! 1230: }
! 1231: break;
! 1232: }
! 1233: }
! 1234:
! 1235: /* The low 8 bit must be zero. */
! 1236: SLJIT_ASSERT(!(imm & 0xff));
! 1237:
! 1238: if (!(imm & 0xff000000)) {
! 1239: imm1 = SRC2_IMM | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8);
! 1240: imm2 = SRC2_IMM | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8);
! 1241: }
! 1242: else if (imm & 0xc0000000) {
! 1243: imm1 = SRC2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
! 1244: imm <<= 8;
! 1245: rol += 4;
! 1246:
! 1247: if (!(imm & 0xff000000)) {
! 1248: imm <<= 8;
! 1249: rol += 4;
! 1250: }
! 1251:
! 1252: if (!(imm & 0xf0000000)) {
! 1253: imm <<= 4;
! 1254: rol += 2;
! 1255: }
! 1256:
! 1257: if (!(imm & 0xc0000000)) {
! 1258: imm <<= 2;
! 1259: rol += 1;
! 1260: }
! 1261:
! 1262: if (!(imm & 0x00ffffff))
! 1263: imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8);
! 1264: else
! 1265: return 0;
! 1266: }
! 1267: else {
! 1268: if (!(imm & 0xf0000000)) {
! 1269: imm <<= 4;
! 1270: rol += 2;
! 1271: }
! 1272:
! 1273: if (!(imm & 0xc0000000)) {
! 1274: imm <<= 2;
! 1275: rol += 1;
! 1276: }
! 1277:
! 1278: imm1 = SRC2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
! 1279: imm <<= 8;
! 1280: rol += 4;
! 1281:
! 1282: if (!(imm & 0xf0000000)) {
! 1283: imm <<= 4;
! 1284: rol += 2;
! 1285: }
! 1286:
! 1287: if (!(imm & 0xc0000000)) {
! 1288: imm <<= 2;
! 1289: rol += 1;
! 1290: }
! 1291:
! 1292: if (!(imm & 0x00ffffff))
! 1293: imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8);
! 1294: else
! 1295: return 0;
! 1296: }
! 1297:
! 1298: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(positive ? MOV_DP : MVN_DP, 0, reg, SLJIT_UNUSED, imm1));
! 1299: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(positive ? ORR_DP : BIC_DP, 0, reg, reg, imm2));
! 1300: return 1;
! 1301: }
! 1302: #endif
! 1303:
! 1304: static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_uw imm)
! 1305: {
! 1306: sljit_uw tmp;
! 1307:
! 1308: #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
! 1309: if (!(imm & ~0xffff))
! 1310: return push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff));
! 1311: #endif
! 1312:
! 1313: /* Create imm by 1 inst. */
! 1314: tmp = get_immediate(imm);
! 1315: if (tmp) {
! 1316: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, reg, SLJIT_UNUSED, tmp));
! 1317: return SLJIT_SUCCESS;
! 1318: }
! 1319:
! 1320: tmp = get_immediate(~imm);
! 1321: if (tmp) {
! 1322: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MVN_DP, 0, reg, SLJIT_UNUSED, tmp));
! 1323: return SLJIT_SUCCESS;
! 1324: }
! 1325:
! 1326: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 1327: /* Create imm by 2 inst. */
! 1328: FAIL_IF(generate_int(compiler, reg, imm, 1));
! 1329: FAIL_IF(generate_int(compiler, reg, ~imm, 0));
! 1330:
! 1331: /* Load integer. */
! 1332: return push_inst_with_literal(compiler, EMIT_DATA_TRANSFER(WORD_DATA | LOAD_DATA, 1, 0, reg, TMP_PC, 0), imm);
! 1333: #else
! 1334: return emit_imm(compiler, reg, imm);
! 1335: #endif
! 1336: }
! 1337:
! 1338: /* Can perform an operation using at most 1 instruction. */
! 1339: static int getput_arg_fast(struct sljit_compiler *compiler, int inp_flags, int reg, int arg, sljit_w argw)
! 1340: {
! 1341: sljit_uw imm;
! 1342:
! 1343: if (arg & SLJIT_IMM) {
! 1344: imm = get_immediate(argw);
! 1345: if (imm) {
! 1346: if (inp_flags & ARG_TEST)
! 1347: return 1;
! 1348: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, reg, SLJIT_UNUSED, imm));
! 1349: return -1;
! 1350: }
! 1351: imm = get_immediate(~argw);
! 1352: if (imm) {
! 1353: if (inp_flags & ARG_TEST)
! 1354: return 1;
! 1355: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MVN_DP, 0, reg, SLJIT_UNUSED, imm));
! 1356: return -1;
! 1357: }
! 1358: return (inp_flags & ARG_TEST) ? SLJIT_SUCCESS : 0;
! 1359: }
! 1360:
! 1361: SLJIT_ASSERT(arg & SLJIT_MEM);
! 1362:
! 1363: /* Fast loads/stores. */
! 1364: if (arg & 0xf) {
! 1365: if (!(arg & 0xf0)) {
! 1366: if (IS_TYPE1_TRANSFER(inp_flags)) {
! 1367: if (argw >= 0 && argw <= 0xfff) {
! 1368: if (inp_flags & ARG_TEST)
! 1369: return 1;
! 1370: EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & 0xf, argw));
! 1371: return -1;
! 1372: }
! 1373: if (argw < 0 && argw >= -0xfff) {
! 1374: if (inp_flags & ARG_TEST)
! 1375: return 1;
! 1376: EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, 0, inp_flags & WRITE_BACK, reg, arg & 0xf, -argw));
! 1377: return -1;
! 1378: }
! 1379: }
! 1380: else {
! 1381: if (argw >= 0 && argw <= 0xff) {
! 1382: if (inp_flags & ARG_TEST)
! 1383: return 1;
! 1384: EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & 0xf, TYPE2_TRANSFER_IMM(argw)));
! 1385: return -1;
! 1386: }
! 1387: if (argw < 0 && argw >= -0xff) {
! 1388: if (inp_flags & ARG_TEST)
! 1389: return 1;
! 1390: argw = -argw;
! 1391: EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, 0, inp_flags & WRITE_BACK, reg, arg & 0xf, TYPE2_TRANSFER_IMM(argw)));
! 1392: return -1;
! 1393: }
! 1394: }
! 1395: }
! 1396: else if ((argw & 0x3) == 0 || IS_TYPE1_TRANSFER(inp_flags)) {
! 1397: if (inp_flags & ARG_TEST)
! 1398: return 1;
! 1399: EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & 0xf,
! 1400: RM((arg >> 4) & 0xf) | (IS_TYPE1_TRANSFER(inp_flags) ? SRC2_IMM : 0) | ((argw & 0x3) << 7)));
! 1401: return -1;
! 1402: }
! 1403: }
! 1404:
! 1405: return (inp_flags & ARG_TEST) ? SLJIT_SUCCESS : 0;
! 1406: }
! 1407:
! 1408: /* See getput_arg below.
! 1409: Note: can_cache is called only for binary operators. Those
! 1410: operators always uses word arguments without write back. */
! 1411: static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw)
! 1412: {
! 1413: /* Immediate caching is not supported as it would be an operation on constant arguments. */
! 1414: if (arg & SLJIT_IMM)
! 1415: return 0;
! 1416:
! 1417: /* Always a simple operation. */
! 1418: if (arg & 0xf0)
! 1419: return 0;
! 1420:
! 1421: if (!(arg & 0xf)) {
! 1422: /* Immediate access. */
! 1423: if ((next_arg & SLJIT_MEM) && ((sljit_uw)argw - (sljit_uw)next_argw <= 0xfff || (sljit_uw)next_argw - (sljit_uw)argw <= 0xfff))
! 1424: return 1;
! 1425: return 0;
! 1426: }
! 1427:
! 1428: if (argw <= 0xfffff && argw >= -0xfffff)
! 1429: return 0;
! 1430:
! 1431: if (argw == next_argw && (next_arg & SLJIT_MEM))
! 1432: return 1;
! 1433:
! 1434: if (arg == next_arg && ((sljit_uw)argw - (sljit_uw)next_argw <= 0xfff || (sljit_uw)next_argw - (sljit_uw)argw <= 0xfff))
! 1435: return 1;
! 1436:
! 1437: return 0;
! 1438: }
! 1439:
! 1440: #define GETPUT_ARG_DATA_TRANSFER(add, wb, target, base, imm) \
! 1441: if (max_delta & 0xf00) \
! 1442: FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, add, wb, target, base, imm))); \
! 1443: else \
! 1444: FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, add, wb, target, base, TYPE2_TRANSFER_IMM(imm))));
! 1445:
! 1446: #define TEST_WRITE_BACK() \
! 1447: if (inp_flags & WRITE_BACK) { \
! 1448: tmp_r = arg & 0xf; \
! 1449: if (reg == tmp_r) { \
! 1450: /* This can only happen for stores */ \
! 1451: /* since ldr reg, [reg, ...]! has no meaning */ \
! 1452: SLJIT_ASSERT(!(inp_flags & LOAD_DATA)); \
! 1453: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG3, SLJIT_UNUSED, RM(reg))); \
! 1454: reg = TMP_REG3; \
! 1455: } \
! 1456: }
! 1457:
! 1458: /* Emit the necessary instructions. See can_cache above. */
! 1459: static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, int arg, sljit_w argw, int next_arg, sljit_w next_argw)
! 1460: {
! 1461: int tmp_r;
! 1462: sljit_w max_delta;
! 1463: sljit_w sign;
! 1464:
! 1465: if (arg & SLJIT_IMM) {
! 1466: SLJIT_ASSERT(inp_flags & LOAD_DATA);
! 1467: return load_immediate(compiler, reg, argw);
! 1468: }
! 1469:
! 1470: SLJIT_ASSERT(arg & SLJIT_MEM);
! 1471:
! 1472: tmp_r = (inp_flags & LOAD_DATA) ? reg : TMP_REG3;
! 1473: max_delta = IS_TYPE1_TRANSFER(inp_flags) ? 0xfff : 0xff;
! 1474:
! 1475: if ((arg & 0xf) == SLJIT_UNUSED) {
! 1476: /* Write back is not used. */
! 1477: if ((compiler->cache_arg & SLJIT_IMM) && (((sljit_uw)argw - (sljit_uw)compiler->cache_argw) <= (sljit_uw)max_delta || ((sljit_uw)compiler->cache_argw - (sljit_uw)argw) <= (sljit_uw)max_delta)) {
! 1478: if (((sljit_uw)argw - (sljit_uw)compiler->cache_argw) <= (sljit_uw)max_delta) {
! 1479: sign = 1;
! 1480: argw = argw - compiler->cache_argw;
! 1481: }
! 1482: else {
! 1483: sign = 0;
! 1484: argw = compiler->cache_argw - argw;
! 1485: }
! 1486:
! 1487: if (max_delta & 0xf00) {
! 1488: EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, sign, 0, reg, TMP_REG3, argw));
! 1489: }
! 1490: else {
! 1491: EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, sign, 0, reg, TMP_REG3, TYPE2_TRANSFER_IMM(argw)));
! 1492: }
! 1493: return SLJIT_SUCCESS;
! 1494: }
! 1495:
! 1496: /* With write back, we can create some sophisticated loads, but
! 1497: it is hard to decide whether we should convert downward (0s) or upward (1s). */
! 1498: if ((next_arg & SLJIT_MEM) && ((sljit_uw)argw - (sljit_uw)next_argw <= (sljit_uw)max_delta || (sljit_uw)next_argw - (sljit_uw)argw <= (sljit_uw)max_delta)) {
! 1499: SLJIT_ASSERT(inp_flags & LOAD_DATA);
! 1500:
! 1501: compiler->cache_arg = SLJIT_IMM;
! 1502: compiler->cache_argw = argw;
! 1503: tmp_r = TMP_REG3;
! 1504: }
! 1505:
! 1506: FAIL_IF(load_immediate(compiler, tmp_r, argw));
! 1507: GETPUT_ARG_DATA_TRANSFER(1, 0, reg, tmp_r, 0);
! 1508: return SLJIT_SUCCESS;
! 1509: }
! 1510:
! 1511: /* Extended imm addressing for [reg+imm] format. */
! 1512: sign = (max_delta << 8) | 0xff;
! 1513: if (!(arg & 0xf0) && argw <= sign && argw >= -sign) {
! 1514: TEST_WRITE_BACK();
! 1515: if (argw >= 0) {
! 1516: sign = 1;
! 1517: }
! 1518: else {
! 1519: sign = 0;
! 1520: argw = -argw;
! 1521: }
! 1522:
! 1523: /* Optimization: add is 0x4, sub is 0x2. Sign is 1 for add and 0 for sub. */
! 1524: if (max_delta & 0xf00)
! 1525: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP << sign, 0, tmp_r, arg & 0xf, SRC2_IMM | (argw >> 12) | 0xa00));
! 1526: else
! 1527: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP << sign, 0, tmp_r, arg & 0xf, SRC2_IMM | (argw >> 8) | 0xc00));
! 1528:
! 1529: argw &= max_delta;
! 1530: GETPUT_ARG_DATA_TRANSFER(sign, inp_flags & WRITE_BACK, reg, tmp_r, argw);
! 1531: return SLJIT_SUCCESS;
! 1532: }
! 1533:
! 1534: if (arg & 0xf0) {
! 1535: SLJIT_ASSERT((argw & 0x3) && !(max_delta & 0xf00));
! 1536: if (inp_flags & WRITE_BACK)
! 1537: tmp_r = arg & 0xf;
! 1538: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP, 0, tmp_r, arg & 0xf, RM((arg >> 4) & 0xf) | ((argw & 0x3) << 7)));
! 1539: EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, 1, 0, reg, tmp_r, TYPE2_TRANSFER_IMM(0)));
! 1540: return SLJIT_SUCCESS;
! 1541: }
! 1542:
! 1543: if (compiler->cache_arg == arg && ((sljit_uw)argw - (sljit_uw)compiler->cache_argw) <= (sljit_uw)max_delta) {
! 1544: SLJIT_ASSERT(!(inp_flags & WRITE_BACK));
! 1545: argw = argw - compiler->cache_argw;
! 1546: GETPUT_ARG_DATA_TRANSFER(1, 0, reg, TMP_REG3, argw);
! 1547: return SLJIT_SUCCESS;
! 1548: }
! 1549:
! 1550: if (compiler->cache_arg == arg && ((sljit_uw)compiler->cache_argw - (sljit_uw)argw) <= (sljit_uw)max_delta) {
! 1551: SLJIT_ASSERT(!(inp_flags & WRITE_BACK));
! 1552: argw = compiler->cache_argw - argw;
! 1553: GETPUT_ARG_DATA_TRANSFER(0, 0, reg, TMP_REG3, argw);
! 1554: return SLJIT_SUCCESS;
! 1555: }
! 1556:
! 1557: if ((compiler->cache_arg & SLJIT_IMM) && compiler->cache_argw == argw) {
! 1558: TEST_WRITE_BACK();
! 1559: EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & 0xf, RM(TMP_REG3) | (max_delta & 0xf00 ? SRC2_IMM : 0)));
! 1560: return SLJIT_SUCCESS;
! 1561: }
! 1562:
! 1563: if (argw == next_argw && (next_arg & SLJIT_MEM)) {
! 1564: SLJIT_ASSERT(inp_flags & LOAD_DATA);
! 1565: FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
! 1566:
! 1567: compiler->cache_arg = SLJIT_IMM;
! 1568: compiler->cache_argw = argw;
! 1569:
! 1570: TEST_WRITE_BACK();
! 1571: EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & 0xf, RM(TMP_REG3) | (max_delta & 0xf00 ? SRC2_IMM : 0)));
! 1572: return SLJIT_SUCCESS;
! 1573: }
! 1574:
! 1575: if (arg == next_arg && !(inp_flags & WRITE_BACK) && ((sljit_uw)argw - (sljit_uw)next_argw <= (sljit_uw)max_delta || (sljit_uw)next_argw - (sljit_uw)argw <= (sljit_uw)max_delta)) {
! 1576: SLJIT_ASSERT(inp_flags & LOAD_DATA);
! 1577: FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
! 1578: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG3, TMP_REG3, reg_map[arg & 0xf]));
! 1579:
! 1580: compiler->cache_arg = arg;
! 1581: compiler->cache_argw = argw;
! 1582:
! 1583: GETPUT_ARG_DATA_TRANSFER(1, 0, reg, TMP_REG3, 0);
! 1584: return SLJIT_SUCCESS;
! 1585: }
! 1586:
! 1587: if ((arg & 0xf) == tmp_r) {
! 1588: compiler->cache_arg = SLJIT_IMM;
! 1589: compiler->cache_argw = argw;
! 1590: tmp_r = TMP_REG3;
! 1591: }
! 1592:
! 1593: FAIL_IF(load_immediate(compiler, tmp_r, argw));
! 1594: EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & 0xf, reg_map[tmp_r] | (max_delta & 0xf00 ? SRC2_IMM : 0)));
! 1595: return SLJIT_SUCCESS;
! 1596: }
! 1597:
! 1598: static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags,
! 1599: int dst, sljit_w dstw,
! 1600: int src1, sljit_w src1w,
! 1601: int src2, sljit_w src2w)
! 1602: {
! 1603: /* arg1 goes to TMP_REG1 or src reg
! 1604: arg2 goes to TMP_REG2, imm or src reg
! 1605: TMP_REG3 can be used for caching
! 1606: result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
! 1607:
! 1608: /* We prefers register and simple consts. */
! 1609: int dst_r;
! 1610: int src1_r;
! 1611: int src2_r = 0;
! 1612: int sugg_src2_r = TMP_REG2;
! 1613: int flags = GET_FLAGS(op) ? SET_FLAGS : 0;
! 1614:
! 1615: compiler->cache_arg = 0;
! 1616: compiler->cache_argw = 0;
! 1617:
! 1618: /* Destination check. */
! 1619: if (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REG3) {
! 1620: dst_r = dst;
! 1621: flags |= REG_DEST;
! 1622: if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
! 1623: sugg_src2_r = dst_r;
! 1624: }
! 1625: else if (dst == SLJIT_UNUSED) {
! 1626: if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM))
! 1627: return SLJIT_SUCCESS;
! 1628: dst_r = TMP_REG2;
! 1629: }
! 1630: else {
! 1631: SLJIT_ASSERT(dst & SLJIT_MEM);
! 1632: if (getput_arg_fast(compiler, inp_flags | ARG_TEST, TMP_REG2, dst, dstw)) {
! 1633: flags |= FAST_DEST;
! 1634: dst_r = TMP_REG2;
! 1635: }
! 1636: else {
! 1637: flags |= SLOW_DEST;
! 1638: dst_r = 0;
! 1639: }
! 1640: }
! 1641:
! 1642: /* Source 1. */
! 1643: if (src1 >= SLJIT_TEMPORARY_REG1 && src1 <= TMP_REG3)
! 1644: src1_r = src1;
! 1645: else if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= TMP_REG3) {
! 1646: flags |= ARGS_SWAPPED;
! 1647: src1_r = src2;
! 1648: src2 = src1;
! 1649: src2w = src1w;
! 1650: }
! 1651: else {
! 1652: if ((inp_flags & ALLOW_ANY_IMM) && (src1 & SLJIT_IMM)) {
! 1653: /* The second check will generate a hit. */
! 1654: src2_r = get_immediate(src1w);
! 1655: if (src2_r) {
! 1656: flags |= ARGS_SWAPPED;
! 1657: src1 = src2;
! 1658: src1w = src2w;
! 1659: }
! 1660: if (inp_flags & ALLOW_INV_IMM) {
! 1661: src2_r = get_immediate(~src1w);
! 1662: if (src2_r) {
! 1663: flags |= ARGS_SWAPPED | INV_IMM;
! 1664: src1 = src2;
! 1665: src1w = src2w;
! 1666: }
! 1667: }
! 1668: }
! 1669:
! 1670: src1_r = 0;
! 1671: if (getput_arg_fast(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w)) {
! 1672: FAIL_IF(compiler->error);
! 1673: src1_r = TMP_REG1;
! 1674: }
! 1675: }
! 1676:
! 1677: /* Source 2. */
! 1678: if (src2_r == 0) {
! 1679: if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= TMP_REG3) {
! 1680: src2_r = src2;
! 1681: flags |= REG_SOURCE;
! 1682: if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_SI)
! 1683: dst_r = src2_r;
! 1684: }
! 1685: else do { /* do { } while(0) is used because of breaks. */
! 1686: if ((inp_flags & ALLOW_ANY_IMM) && (src2 & SLJIT_IMM)) {
! 1687: src2_r = get_immediate(src2w);
! 1688: if (src2_r)
! 1689: break;
! 1690: if (inp_flags & ALLOW_INV_IMM) {
! 1691: src2_r = get_immediate(~src2w);
! 1692: if (src2_r) {
! 1693: flags |= INV_IMM;
! 1694: break;
! 1695: }
! 1696: }
! 1697: }
! 1698:
! 1699: /* src2_r is 0. */
! 1700: if (getput_arg_fast(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w)) {
! 1701: FAIL_IF(compiler->error);
! 1702: src2_r = sugg_src2_r;
! 1703: }
! 1704: } while (0);
! 1705: }
! 1706:
! 1707: /* src1_r, src2_r and dst_r can be zero (=unprocessed) or non-zero.
! 1708: If they are zero, they must not be registers. */
! 1709: if (src1_r == 0 && src2_r == 0 && dst_r == 0) {
! 1710: if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
! 1711: SLJIT_ASSERT(!(flags & ARGS_SWAPPED));
! 1712: flags |= ARGS_SWAPPED;
! 1713: FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src2, src2w, src1, src1w));
! 1714: FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG2, src1, src1w, dst, dstw));
! 1715: }
! 1716: else {
! 1717: FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
! 1718: FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG2, src2, src2w, dst, dstw));
! 1719: }
! 1720: src1_r = TMP_REG1;
! 1721: src2_r = TMP_REG2;
! 1722: }
! 1723: else if (src1_r == 0 && src2_r == 0) {
! 1724: FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
! 1725: src1_r = TMP_REG1;
! 1726: }
! 1727: else if (src1_r == 0 && dst_r == 0) {
! 1728: FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
! 1729: src1_r = TMP_REG1;
! 1730: }
! 1731: else if (src2_r == 0 && dst_r == 0) {
! 1732: FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w, dst, dstw));
! 1733: src2_r = sugg_src2_r;
! 1734: }
! 1735:
! 1736: if (dst_r == 0)
! 1737: dst_r = TMP_REG2;
! 1738:
! 1739: if (src1_r == 0) {
! 1740: FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, 0, 0));
! 1741: src1_r = TMP_REG1;
! 1742: }
! 1743:
! 1744: if (src2_r == 0) {
! 1745: FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w, 0, 0));
! 1746: src2_r = sugg_src2_r;
! 1747: }
! 1748:
! 1749: FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
! 1750:
! 1751: if (flags & (FAST_DEST | SLOW_DEST)) {
! 1752: if (flags & FAST_DEST)
! 1753: FAIL_IF(getput_arg_fast(compiler, inp_flags, dst_r, dst, dstw));
! 1754: else
! 1755: FAIL_IF(getput_arg(compiler, inp_flags, dst_r, dst, dstw, 0, 0));
! 1756: }
! 1757: return SLJIT_SUCCESS;
! 1758: }
! 1759:
! 1760: #ifdef __cplusplus
! 1761: extern "C" {
! 1762: #endif
! 1763:
! 1764: #if defined(__GNUC__)
! 1765: extern unsigned int __aeabi_uidivmod(unsigned numerator, unsigned denominator);
! 1766: extern unsigned int __aeabi_idivmod(unsigned numerator, unsigned denominator);
! 1767: #else
! 1768: #error "Software divmod functions are needed"
! 1769: #endif
! 1770:
! 1771: #ifdef __cplusplus
! 1772: }
! 1773: #endif
! 1774:
! 1775: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op)
! 1776: {
! 1777: CHECK_ERROR();
! 1778: check_sljit_emit_op0(compiler, op);
! 1779:
! 1780: op = GET_OPCODE(op);
! 1781: switch (op) {
! 1782: case SLJIT_BREAKPOINT:
! 1783: EMIT_INSTRUCTION(BKPT);
! 1784: break;
! 1785: case SLJIT_NOP:
! 1786: EMIT_INSTRUCTION(NOP);
! 1787: break;
! 1788: case SLJIT_UMUL:
! 1789: case SLJIT_SMUL:
! 1790: #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
! 1791: return push_inst(compiler, (op == SLJIT_UMUL ? UMULL : SMULL)
! 1792: | (reg_map[SLJIT_TEMPORARY_REG2] << 16)
! 1793: | (reg_map[SLJIT_TEMPORARY_REG1] << 12)
! 1794: | (reg_map[SLJIT_TEMPORARY_REG1] << 8)
! 1795: | reg_map[SLJIT_TEMPORARY_REG2]);
! 1796: #else
! 1797: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG1, SLJIT_UNUSED, RM(SLJIT_TEMPORARY_REG2)));
! 1798: return push_inst(compiler, (op == SLJIT_UMUL ? UMULL : SMULL)
! 1799: | (reg_map[SLJIT_TEMPORARY_REG2] << 16)
! 1800: | (reg_map[SLJIT_TEMPORARY_REG1] << 12)
! 1801: | (reg_map[SLJIT_TEMPORARY_REG1] << 8)
! 1802: | reg_map[TMP_REG1]);
! 1803: #endif
! 1804: case SLJIT_UDIV:
! 1805: case SLJIT_SDIV:
! 1806: if (compiler->temporaries >= 3)
! 1807: EMIT_INSTRUCTION(0xe52d2008 /* str r2, [sp, #-8]! */);
! 1808: #if defined(__GNUC__)
! 1809: FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM,
! 1810: (op == SLJIT_UDIV ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod))));
! 1811: #else
! 1812: #error "Software divmod functions are needed"
! 1813: #endif
! 1814: if (compiler->temporaries >= 3)
! 1815: return push_inst(compiler, 0xe49d2008 /* ldr r2, [sp], #8 */);
! 1816: return SLJIT_SUCCESS;
! 1817: }
! 1818:
! 1819: return SLJIT_SUCCESS;
! 1820: }
! 1821:
! 1822: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int op,
! 1823: int dst, sljit_w dstw,
! 1824: int src, sljit_w srcw)
! 1825: {
! 1826: CHECK_ERROR();
! 1827: check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw);
! 1828:
! 1829: switch (GET_OPCODE(op)) {
! 1830: case SLJIT_MOV:
! 1831: case SLJIT_MOV_UI:
! 1832: case SLJIT_MOV_SI:
! 1833: return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw);
! 1834:
! 1835: case SLJIT_MOV_UB:
! 1836: return emit_op(compiler, SLJIT_MOV_UB, ALLOW_ANY_IMM | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned char)srcw : srcw);
! 1837:
! 1838: case SLJIT_MOV_SB:
! 1839: return emit_op(compiler, SLJIT_MOV_SB, ALLOW_ANY_IMM | SIGNED_DATA | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed char)srcw : srcw);
! 1840:
! 1841: case SLJIT_MOV_UH:
! 1842: return emit_op(compiler, SLJIT_MOV_UH, ALLOW_ANY_IMM | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned short)srcw : srcw);
! 1843:
! 1844: case SLJIT_MOV_SH:
! 1845: return emit_op(compiler, SLJIT_MOV_SH, ALLOW_ANY_IMM | SIGNED_DATA | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed short)srcw : srcw);
! 1846:
! 1847: case SLJIT_MOVU:
! 1848: case SLJIT_MOVU_UI:
! 1849: case SLJIT_MOVU_SI:
! 1850: return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
! 1851:
! 1852: case SLJIT_MOVU_UB:
! 1853: return emit_op(compiler, SLJIT_MOV_UB, ALLOW_ANY_IMM | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned char)srcw : srcw);
! 1854:
! 1855: case SLJIT_MOVU_SB:
! 1856: return emit_op(compiler, SLJIT_MOV_SB, ALLOW_ANY_IMM | SIGNED_DATA | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed char)srcw : srcw);
! 1857:
! 1858: case SLJIT_MOVU_UH:
! 1859: return emit_op(compiler, SLJIT_MOV_UH, ALLOW_ANY_IMM | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned short)srcw : srcw);
! 1860:
! 1861: case SLJIT_MOVU_SH:
! 1862: return emit_op(compiler, SLJIT_MOV_SH, ALLOW_ANY_IMM | SIGNED_DATA | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed short)srcw : srcw);
! 1863:
! 1864: case SLJIT_NOT:
! 1865: return emit_op(compiler, op, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw);
! 1866:
! 1867: case SLJIT_NEG:
! 1868: #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG)
! 1869: compiler->skip_checks = 1;
! 1870: #endif
! 1871: return sljit_emit_op2(compiler, SLJIT_SUB | GET_FLAGS(op), dst, dstw, SLJIT_IMM, 0, src, srcw);
! 1872:
! 1873: case SLJIT_CLZ:
! 1874: return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src, srcw);
! 1875: }
! 1876:
! 1877: return SLJIT_SUCCESS;
! 1878: }
! 1879:
! 1880: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int op,
! 1881: int dst, sljit_w dstw,
! 1882: int src1, sljit_w src1w,
! 1883: int src2, sljit_w src2w)
! 1884: {
! 1885: CHECK_ERROR();
! 1886: check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w);
! 1887:
! 1888: switch (GET_OPCODE(op)) {
! 1889: case SLJIT_ADD:
! 1890: case SLJIT_ADDC:
! 1891: case SLJIT_SUB:
! 1892: case SLJIT_SUBC:
! 1893: case SLJIT_OR:
! 1894: case SLJIT_XOR:
! 1895: return emit_op(compiler, op, ALLOW_IMM, dst, dstw, src1, src1w, src2, src2w);
! 1896:
! 1897: case SLJIT_MUL:
! 1898: return emit_op(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w);
! 1899:
! 1900: case SLJIT_AND:
! 1901: return emit_op(compiler, op, ALLOW_ANY_IMM, dst, dstw, src1, src1w, src2, src2w);
! 1902:
! 1903: case SLJIT_SHL:
! 1904: case SLJIT_LSHR:
! 1905: case SLJIT_ASHR:
! 1906: if (src2 & SLJIT_IMM) {
! 1907: compiler->shift_imm = src2w & 0x1f;
! 1908: return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src1, src1w);
! 1909: }
! 1910: else {
! 1911: compiler->shift_imm = 0x20;
! 1912: return emit_op(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w);
! 1913: }
! 1914: }
! 1915:
! 1916: return SLJIT_SUCCESS;
! 1917: }
! 1918:
! 1919: SLJIT_API_FUNC_ATTRIBUTE int sljit_get_register_index(int reg)
! 1920: {
! 1921: check_sljit_get_register_index(reg);
! 1922: return reg_map[reg];
! 1923: }
! 1924:
! 1925: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compiler,
! 1926: void *instruction, int size)
! 1927: {
! 1928: CHECK_ERROR();
! 1929: check_sljit_emit_op_custom(compiler, instruction, size);
! 1930: SLJIT_ASSERT(size == 4);
! 1931:
! 1932: return push_inst(compiler, *(sljit_uw*)instruction);
! 1933: }
! 1934:
! 1935: /* --------------------------------------------------------------------- */
! 1936: /* Floating point operators */
! 1937: /* --------------------------------------------------------------------- */
! 1938:
! 1939: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 1940:
! 1941: /* 0 - no fpu
! 1942: 1 - vfp */
! 1943: static int arm_fpu_type = -1;
! 1944:
! 1945: static void init_compiler()
! 1946: {
! 1947: if (arm_fpu_type != -1)
! 1948: return;
! 1949:
! 1950: /* TODO: Only the OS can help to determine the correct fpu type. */
! 1951: arm_fpu_type = 1;
! 1952: }
! 1953:
! 1954: SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void)
! 1955: {
! 1956: if (arm_fpu_type == -1)
! 1957: init_compiler();
! 1958: return arm_fpu_type;
! 1959: }
! 1960:
! 1961: #else
! 1962:
! 1963: #define arm_fpu_type 1
! 1964:
! 1965: SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void)
! 1966: {
! 1967: /* Always available. */
! 1968: return 1;
! 1969: }
! 1970:
! 1971: #endif
! 1972:
! 1973: #define EMIT_FPU_DATA_TRANSFER(add, load, base, freg, offs) \
! 1974: (VSTR | ((add) << 23) | ((load) << 20) | (reg_map[base] << 16) | (freg << 12) | (offs))
! 1975: #define EMIT_FPU_OPERATION(opcode, dst, src1, src2) \
! 1976: ((opcode) | ((dst) << 12) | (src1) | ((src2) << 16))
! 1977:
! 1978: static int emit_fpu_data_transfer(struct sljit_compiler *compiler, int fpu_reg, int load, int arg, sljit_w argw)
! 1979: {
! 1980: SLJIT_ASSERT(arg & SLJIT_MEM);
! 1981:
! 1982: /* Fast loads and stores. */
! 1983: if ((arg & 0xf) && !(arg & 0xf0) && (argw & 0x3) == 0) {
! 1984: if (argw >= 0 && argw <= 0x3ff) {
! 1985: EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load, arg & 0xf, fpu_reg, argw >> 2));
! 1986: return SLJIT_SUCCESS;
! 1987: }
! 1988: if (argw < 0 && argw >= -0x3ff) {
! 1989: EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(0, load, arg & 0xf, fpu_reg, (-argw) >> 2));
! 1990: return SLJIT_SUCCESS;
! 1991: }
! 1992: if (argw >= 0 && argw <= 0x3ffff) {
! 1993: SLJIT_ASSERT(get_immediate(argw & 0x3fc00));
! 1994: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG1, arg & 0xf, get_immediate(argw & 0x3fc00)));
! 1995: argw &= 0x3ff;
! 1996: EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load, TMP_REG1, fpu_reg, argw >> 2));
! 1997: return SLJIT_SUCCESS;
! 1998: }
! 1999: if (argw < 0 && argw >= -0x3ffff) {
! 2000: argw = -argw;
! 2001: SLJIT_ASSERT(get_immediate(argw & 0x3fc00));
! 2002: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP, 0, TMP_REG1, arg & 0xf, get_immediate(argw & 0x3fc00)));
! 2003: argw &= 0x3ff;
! 2004: EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(0, load, TMP_REG1, fpu_reg, argw >> 2));
! 2005: return SLJIT_SUCCESS;
! 2006: }
! 2007: }
! 2008:
! 2009: if (arg & 0xf0) {
! 2010: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG1, arg & 0xf, RM((arg >> 4) & 0xf) | ((argw & 0x3) << 7)));
! 2011: EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load, TMP_REG1, fpu_reg, 0));
! 2012: return SLJIT_SUCCESS;
! 2013: }
! 2014:
! 2015: if (compiler->cache_arg == arg && ((argw - compiler->cache_argw) & 0x3) == 0) {
! 2016: if (((sljit_uw)argw - (sljit_uw)compiler->cache_argw) <= 0x3ff) {
! 2017: EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load, TMP_REG3, fpu_reg, (argw - compiler->cache_argw) >> 2));
! 2018: return SLJIT_SUCCESS;
! 2019: }
! 2020: if (((sljit_uw)compiler->cache_argw - (sljit_uw)argw) <= 0x3ff) {
! 2021: EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(0, load, TMP_REG3, fpu_reg, (compiler->cache_argw - argw) >> 2));
! 2022: return SLJIT_SUCCESS;
! 2023: }
! 2024: }
! 2025:
! 2026: compiler->cache_arg = arg;
! 2027: compiler->cache_argw = argw;
! 2028: if (arg & 0xf) {
! 2029: FAIL_IF(load_immediate(compiler, TMP_REG1, argw));
! 2030: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG3, arg & 0xf, reg_map[TMP_REG1]));
! 2031: }
! 2032: else
! 2033: FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
! 2034:
! 2035: EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load, TMP_REG3, fpu_reg, 0));
! 2036: return SLJIT_SUCCESS;
! 2037: }
! 2038:
! 2039: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, int op,
! 2040: int dst, sljit_w dstw,
! 2041: int src, sljit_w srcw)
! 2042: {
! 2043: int dst_freg;
! 2044:
! 2045: CHECK_ERROR();
! 2046: check_sljit_emit_fop1(compiler, op, dst, dstw, src, srcw);
! 2047:
! 2048: compiler->cache_arg = 0;
! 2049: compiler->cache_argw = 0;
! 2050:
! 2051: if (GET_OPCODE(op) == SLJIT_FCMP) {
! 2052: if (dst > SLJIT_FLOAT_REG4) {
! 2053: FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 1, dst, dstw));
! 2054: dst = TMP_FREG1;
! 2055: }
! 2056: if (src > SLJIT_FLOAT_REG4) {
! 2057: FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG2, 1, src, srcw));
! 2058: src = TMP_FREG2;
! 2059: }
! 2060: EMIT_INSTRUCTION(VCMP_F64 | (dst << 12) | src);
! 2061: EMIT_INSTRUCTION(VMRS);
! 2062: return SLJIT_SUCCESS;
! 2063: }
! 2064:
! 2065: dst_freg = (dst > SLJIT_FLOAT_REG4) ? TMP_FREG1 : dst;
! 2066:
! 2067: if (src > SLJIT_FLOAT_REG4) {
! 2068: FAIL_IF(emit_fpu_data_transfer(compiler, dst_freg, 1, src, srcw));
! 2069: src = dst_freg;
! 2070: }
! 2071:
! 2072: switch (op) {
! 2073: case SLJIT_FMOV:
! 2074: if (src != dst_freg && dst_freg != TMP_FREG1)
! 2075: EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VMOV_F64, dst_freg, src, 0));
! 2076: break;
! 2077: case SLJIT_FNEG:
! 2078: EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VNEG_F64, dst_freg, src, 0));
! 2079: break;
! 2080: case SLJIT_FABS:
! 2081: EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VABS_F64, dst_freg, src, 0));
! 2082: break;
! 2083: }
! 2084:
! 2085: if (dst_freg == TMP_FREG1)
! 2086: FAIL_IF(emit_fpu_data_transfer(compiler, src, 0, dst, dstw));
! 2087:
! 2088: return SLJIT_SUCCESS;
! 2089: }
! 2090:
! 2091: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, int op,
! 2092: int dst, sljit_w dstw,
! 2093: int src1, sljit_w src1w,
! 2094: int src2, sljit_w src2w)
! 2095: {
! 2096: int dst_freg;
! 2097:
! 2098: CHECK_ERROR();
! 2099: check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w);
! 2100:
! 2101: compiler->cache_arg = 0;
! 2102: compiler->cache_argw = 0;
! 2103:
! 2104: dst_freg = (dst > SLJIT_FLOAT_REG4) ? TMP_FREG1 : dst;
! 2105:
! 2106: if (src2 > SLJIT_FLOAT_REG4) {
! 2107: FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG2, 1, src2, src2w));
! 2108: src2 = TMP_FREG2;
! 2109: }
! 2110:
! 2111: if (src1 > SLJIT_FLOAT_REG4) {
! 2112: FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 1, src1, src1w));
! 2113: src1 = TMP_FREG1;
! 2114: }
! 2115:
! 2116: switch (op) {
! 2117: case SLJIT_FADD:
! 2118: EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VADD_F64, dst_freg, src2, src1));
! 2119: break;
! 2120:
! 2121: case SLJIT_FSUB:
! 2122: EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VSUB_F64, dst_freg, src2, src1));
! 2123: break;
! 2124:
! 2125: case SLJIT_FMUL:
! 2126: EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VMUL_F64, dst_freg, src2, src1));
! 2127: break;
! 2128:
! 2129: case SLJIT_FDIV:
! 2130: EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VDIV_F64, dst_freg, src2, src1));
! 2131: break;
! 2132: }
! 2133:
! 2134: if (dst_freg == TMP_FREG1)
! 2135: FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 0, dst, dstw));
! 2136:
! 2137: return SLJIT_SUCCESS;
! 2138: }
! 2139:
! 2140: /* --------------------------------------------------------------------- */
! 2141: /* Other instructions */
! 2142: /* --------------------------------------------------------------------- */
! 2143:
! 2144: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw, int args, int temporaries, int saveds, int local_size)
! 2145: {
! 2146: int size;
! 2147:
! 2148: CHECK_ERROR();
! 2149: check_sljit_emit_fast_enter(compiler, dst, dstw, args, temporaries, saveds, local_size);
! 2150:
! 2151: compiler->temporaries = temporaries;
! 2152: compiler->saveds = saveds;
! 2153:
! 2154: size = (1 + saveds) * sizeof(sljit_uw);
! 2155: if (temporaries >= 4)
! 2156: size += (temporaries - 3) * sizeof(sljit_uw);
! 2157: local_size += size;
! 2158: local_size = (local_size + 7) & ~7;
! 2159: local_size -= size;
! 2160: compiler->local_size = local_size;
! 2161:
! 2162: if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS)
! 2163: return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, RM(TMP_REG3)));
! 2164: else if (dst & SLJIT_MEM) {
! 2165: if (getput_arg_fast(compiler, WORD_DATA, TMP_REG3, dst, dstw))
! 2166: return compiler->error;
! 2167: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG2, SLJIT_UNUSED, RM(TMP_REG3)));
! 2168: compiler->cache_arg = 0;
! 2169: compiler->cache_argw = 0;
! 2170: return getput_arg(compiler, WORD_DATA, TMP_REG2, dst, dstw, 0, 0);
! 2171: }
! 2172:
! 2173: return SLJIT_SUCCESS;
! 2174: }
! 2175:
! 2176: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw)
! 2177: {
! 2178: CHECK_ERROR();
! 2179: check_sljit_emit_fast_return(compiler, src, srcw);
! 2180:
! 2181: if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS)
! 2182: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG3, SLJIT_UNUSED, RM(src)));
! 2183: else if (src & SLJIT_MEM) {
! 2184: if (getput_arg_fast(compiler, WORD_DATA | LOAD_DATA, TMP_REG3, src, srcw))
! 2185: FAIL_IF(compiler->error);
! 2186: else {
! 2187: compiler->cache_arg = 0;
! 2188: compiler->cache_argw = 0;
! 2189: FAIL_IF(getput_arg(compiler, WORD_DATA | LOAD_DATA, TMP_REG2, src, srcw, 0, 0));
! 2190: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG3, SLJIT_UNUSED, RM(TMP_REG2)));
! 2191: }
! 2192: }
! 2193: else if (src & SLJIT_IMM)
! 2194: FAIL_IF(load_immediate(compiler, TMP_REG3, srcw));
! 2195: return push_inst(compiler, BLX | RM(TMP_REG3));
! 2196: }
! 2197:
! 2198: /* --------------------------------------------------------------------- */
! 2199: /* Conditional instructions */
! 2200: /* --------------------------------------------------------------------- */
! 2201:
! 2202: static sljit_uw get_cc(int type)
! 2203: {
! 2204: switch (type) {
! 2205: case SLJIT_C_EQUAL:
! 2206: case SLJIT_C_MUL_NOT_OVERFLOW:
! 2207: case SLJIT_C_FLOAT_EQUAL:
! 2208: return 0x00000000;
! 2209:
! 2210: case SLJIT_C_NOT_EQUAL:
! 2211: case SLJIT_C_MUL_OVERFLOW:
! 2212: case SLJIT_C_FLOAT_NOT_EQUAL:
! 2213: return 0x10000000;
! 2214:
! 2215: case SLJIT_C_LESS:
! 2216: case SLJIT_C_FLOAT_LESS:
! 2217: return 0x30000000;
! 2218:
! 2219: case SLJIT_C_GREATER_EQUAL:
! 2220: case SLJIT_C_FLOAT_GREATER_EQUAL:
! 2221: return 0x20000000;
! 2222:
! 2223: case SLJIT_C_GREATER:
! 2224: case SLJIT_C_FLOAT_GREATER:
! 2225: return 0x80000000;
! 2226:
! 2227: case SLJIT_C_LESS_EQUAL:
! 2228: case SLJIT_C_FLOAT_LESS_EQUAL:
! 2229: return 0x90000000;
! 2230:
! 2231: case SLJIT_C_SIG_LESS:
! 2232: return 0xb0000000;
! 2233:
! 2234: case SLJIT_C_SIG_GREATER_EQUAL:
! 2235: return 0xa0000000;
! 2236:
! 2237: case SLJIT_C_SIG_GREATER:
! 2238: return 0xc0000000;
! 2239:
! 2240: case SLJIT_C_SIG_LESS_EQUAL:
! 2241: return 0xd0000000;
! 2242:
! 2243: case SLJIT_C_OVERFLOW:
! 2244: case SLJIT_C_FLOAT_NAN:
! 2245: return 0x60000000;
! 2246:
! 2247: case SLJIT_C_NOT_OVERFLOW:
! 2248: case SLJIT_C_FLOAT_NOT_NAN:
! 2249: return 0x70000000;
! 2250:
! 2251: default: /* SLJIT_JUMP */
! 2252: return 0xe0000000;
! 2253: }
! 2254: }
! 2255:
! 2256: SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
! 2257: {
! 2258: struct sljit_label *label;
! 2259:
! 2260: CHECK_ERROR_PTR();
! 2261: check_sljit_emit_label(compiler);
! 2262:
! 2263: if (compiler->last_label && compiler->last_label->size == compiler->size)
! 2264: return compiler->last_label;
! 2265:
! 2266: label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
! 2267: PTR_FAIL_IF(!label);
! 2268: set_label(label, compiler);
! 2269: return label;
! 2270: }
! 2271:
! 2272: SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, int type)
! 2273: {
! 2274: struct sljit_jump *jump;
! 2275:
! 2276: CHECK_ERROR_PTR();
! 2277: check_sljit_emit_jump(compiler, type);
! 2278:
! 2279: jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
! 2280: PTR_FAIL_IF(!jump);
! 2281: set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
! 2282: type &= 0xff;
! 2283:
! 2284: /* In ARM, we don't need to touch the arguments. */
! 2285: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 2286: if (type >= SLJIT_FAST_CALL)
! 2287: PTR_FAIL_IF(prepare_blx(compiler));
! 2288: PTR_FAIL_IF(push_inst_with_unique_literal(compiler, ((EMIT_DATA_TRANSFER(WORD_DATA | LOAD_DATA, 1, 0,
! 2289: type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0)) & ~COND_MASK) | get_cc(type), 0));
! 2290:
! 2291: if (jump->flags & SLJIT_REWRITABLE_JUMP) {
! 2292: jump->addr = compiler->size;
! 2293: compiler->patches++;
! 2294: }
! 2295:
! 2296: if (type >= SLJIT_FAST_CALL) {
! 2297: jump->flags |= IS_BL;
! 2298: PTR_FAIL_IF(emit_blx(compiler));
! 2299: }
! 2300:
! 2301: if (!(jump->flags & SLJIT_REWRITABLE_JUMP))
! 2302: jump->addr = compiler->size;
! 2303: #else
! 2304: if (type >= SLJIT_FAST_CALL)
! 2305: jump->flags |= IS_BL;
! 2306: PTR_FAIL_IF(emit_imm(compiler, TMP_REG1, 0));
! 2307: PTR_FAIL_IF(push_inst(compiler, (((type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)) & ~COND_MASK) | get_cc(type)));
! 2308: jump->addr = compiler->size;
! 2309: #endif
! 2310: return jump;
! 2311: }
! 2312:
! 2313: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, int type, int src, sljit_w srcw)
! 2314: {
! 2315: struct sljit_jump *jump;
! 2316:
! 2317: CHECK_ERROR();
! 2318: check_sljit_emit_ijump(compiler, type, src, srcw);
! 2319:
! 2320: /* In ARM, we don't need to touch the arguments. */
! 2321: if (src & SLJIT_IMM) {
! 2322: jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
! 2323: FAIL_IF(!jump);
! 2324: set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0));
! 2325: jump->u.target = srcw;
! 2326:
! 2327: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 2328: if (type >= SLJIT_FAST_CALL)
! 2329: FAIL_IF(prepare_blx(compiler));
! 2330: FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_DATA | LOAD_DATA, 1, 0, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0), 0));
! 2331: if (type >= SLJIT_FAST_CALL)
! 2332: FAIL_IF(emit_blx(compiler));
! 2333: #else
! 2334: FAIL_IF(emit_imm(compiler, TMP_REG1, 0));
! 2335: FAIL_IF(push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)));
! 2336: #endif
! 2337: jump->addr = compiler->size;
! 2338: }
! 2339: else {
! 2340: if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS)
! 2341: return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(src));
! 2342:
! 2343: SLJIT_ASSERT(src & SLJIT_MEM);
! 2344: FAIL_IF(emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, TMP_REG2, 0, TMP_REG1, 0, src, srcw));
! 2345: return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG2));
! 2346: }
! 2347:
! 2348: return SLJIT_SUCCESS;
! 2349: }
! 2350:
! 2351: SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compiler, int op, int dst, sljit_w dstw, int type)
! 2352: {
! 2353: int reg;
! 2354: sljit_uw cc;
! 2355:
! 2356: CHECK_ERROR();
! 2357: check_sljit_emit_cond_value(compiler, op, dst, dstw, type);
! 2358:
! 2359: if (dst == SLJIT_UNUSED)
! 2360: return SLJIT_SUCCESS;
! 2361:
! 2362: cc = get_cc(type);
! 2363: if (GET_OPCODE(op) == SLJIT_OR) {
! 2364: if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) {
! 2365: EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(ORR_DP, 0, dst, dst, SRC2_IMM | 1) & ~COND_MASK) | cc);
! 2366: if (op & SLJIT_SET_E)
! 2367: return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, SET_FLAGS, TMP_REG1, SLJIT_UNUSED, RM(dst)));
! 2368: return SLJIT_SUCCESS;
! 2369: }
! 2370:
! 2371: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG1, SLJIT_UNUSED, SRC2_IMM | 0));
! 2372: EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG1, SLJIT_UNUSED, SRC2_IMM | 1) & ~COND_MASK) | cc);
! 2373: #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG)
! 2374: compiler->skip_checks = 1;
! 2375: #endif
! 2376: return emit_op(compiler, op, ALLOW_IMM, dst, dstw, TMP_REG1, 0, dst, dstw);
! 2377: }
! 2378:
! 2379: reg = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG2;
! 2380:
! 2381: EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, reg, SLJIT_UNUSED, SRC2_IMM | 0));
! 2382: EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(MOV_DP, 0, reg, SLJIT_UNUSED, SRC2_IMM | 1) & ~COND_MASK) | cc);
! 2383:
! 2384: if (reg == TMP_REG2)
! 2385: return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
! 2386: return SLJIT_SUCCESS;
! 2387: }
! 2388:
! 2389: SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w init_value)
! 2390: {
! 2391: struct sljit_const *const_;
! 2392: int reg;
! 2393:
! 2394: CHECK_ERROR_PTR();
! 2395: check_sljit_emit_const(compiler, dst, dstw, init_value);
! 2396:
! 2397: const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
! 2398: PTR_FAIL_IF(!const_);
! 2399:
! 2400: reg = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG2;
! 2401:
! 2402: #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
! 2403: PTR_FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_DATA | LOAD_DATA, 1, 0, reg, TMP_PC, 0), init_value));
! 2404: compiler->patches++;
! 2405: #else
! 2406: PTR_FAIL_IF(emit_imm(compiler, reg, init_value));
! 2407: #endif
! 2408: set_const(const_, compiler);
! 2409:
! 2410: if (reg == TMP_REG2 && dst != SLJIT_UNUSED)
! 2411: if (emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, TMP_REG2, 0))
! 2412: return NULL;
! 2413: return const_;
! 2414: }
! 2415:
! 2416: SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
! 2417: {
! 2418: inline_set_jump_addr(addr, new_addr, 1);
! 2419: }
! 2420:
! 2421: SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant)
! 2422: {
! 2423: inline_set_const(addr, new_constant, 1);
! 2424: }
E-mail: