mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
* lightening/arm-cpu.c (encode_thumb_immediate): Fix return value in third case. Signed-off-by: Ludovic Courtès <ludo@gnu.org>
3108 lines
73 KiB
C
3108 lines
73 KiB
C
/*
|
|
* Copyright (C) 2012-2017,2019-2020 Free Software Foundation, Inc.
|
|
*
|
|
* This file is part of GNU lightning.
|
|
*
|
|
* GNU lightning is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published
|
|
* by the Free Software Foundation; either version 3, or (at your option)
|
|
* any later version.
|
|
*
|
|
* GNU lightning is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
* License for more details.
|
|
*
|
|
* Authors:
|
|
* Paulo Cesar Pereira de Andrade
|
|
*/
|
|
|
|
#define _s20P(d) ((d) >= -(int)0x80000 && d <= 0x7ffff)
|
|
#define _s24P(d) ((d) >= -(int)0x800000 && d <= 0x7fffff)
|
|
#define _u3(v) ((v) & 0x7)
|
|
#define _u4(v) ((v) & 0xf)
|
|
#define _u5(v) ((v) & 0x1f)
|
|
#define _u8(v) ((v) & 0xff)
|
|
#define _u12(v) ((v) & 0xfff)
|
|
#define _u13(v) ((v) & 0x1fff)
|
|
#define _u16(v) ((v) & 0xffff)
|
|
#define _u24(v) ((v) & 0xffffff)
|
|
|
|
#define ARM_CC_EQ 0x00000000 /* Z=1 */
|
|
#define ARM_CC_NE 0x10000000 /* Z=0 */
|
|
#define ARM_CC_HS 0x20000000 /* C=1 */
|
|
#define ARM_CC_LO 0x30000000 /* C=0 */
|
|
#define ARM_CC_MI 0x40000000 /* N=1 */
|
|
#define ARM_CC_VS 0x60000000 /* V=1 */
|
|
#define ARM_CC_VC 0x70000000 /* V=0 */
|
|
#define ARM_CC_HI 0x80000000 /* C=1 && Z=0 */
|
|
#define ARM_CC_LS 0x90000000 /* C=0 || Z=1 */
|
|
#define ARM_CC_GE 0xa0000000 /* N=V */
|
|
#define ARM_CC_LT 0xb0000000 /* N!=V */
|
|
#define ARM_CC_GT 0xc0000000 /* Z=0 && N=V */
|
|
#define ARM_CC_LE 0xd0000000 /* Z=1 || N!=V */
|
|
#define ARM_CC_AL 0xe0000000 /* always */
|
|
#define ARM_CC_NV 0xf0000000 /* reserved */
|
|
#define THUMB_MOV 0x4600
|
|
#define THUMB_MOVI 0x2000
|
|
#define THUMB2_MOVI 0xf0400000
|
|
#define THUMB2_MOVWI 0xf2400000
|
|
#define THUMB2_MOVTI 0xf2c00000
|
|
#define THUMB_MVN 0x43c0
|
|
#define THUMB2_MVN 0xea600000
|
|
#define THUMB2_MVNI 0xf0600000
|
|
#define ARM_S 0x00100000 /* set flags */
|
|
#define THUMB_ADD 0x1800
|
|
#define THUMB_ADDX 0x4400
|
|
#define THUMB2_ADD 0xeb000000
|
|
#define THUMB_ADDI3 0x1c00
|
|
#define THUMB_ADDI8 0x3000
|
|
#define THUMB2_ADDI 0xf1000000
|
|
#define THUMB2_ADDWI 0xf2000000
|
|
#define THUMB_ADC 0x4140
|
|
#define THUMB2_ADC 0xeb400000
|
|
#define THUMB2_ADCI 0xf1400000
|
|
#define THUMB_SUB 0x1a00
|
|
#define THUMB2_SUB 0xeba00000
|
|
#define THUMB_SUBI3 0x1e00
|
|
#define THUMB_SUBI8 0x3800
|
|
#define THUMB2_SUBI 0xf1a00000
|
|
#define THUMB2_SUBWI 0xf2a00000
|
|
#define THUMB_SBC 0x4180
|
|
#define THUMB2_SBC 0xeb600000
|
|
#define THUMB2_SBCI 0xf1600000
|
|
#define THUMB_RSBI 0x4240
|
|
#define THUMB2_RSBI 0xf1c00000
|
|
#define THUMB_MUL 0x4340
|
|
#define THUMB2_MUL 0xfb00f000
|
|
#define THUMB2_UMULL 0xfba00000
|
|
#define THUMB2_SMULL 0xfb800000
|
|
#define THUMB_MLS 0xfb000010
|
|
#define THUMB2_SDIV 0xfb90f0f0
|
|
#define THUMB2_UDIV 0xfbb0f0f0
|
|
#define THUMB_AND 0x4000
|
|
#define THUMB2_AND 0xea000000
|
|
#define THUMB2_ANDI 0xf0000000
|
|
#define THUMB2_BIC 0xea200000
|
|
#define THUMB2_BICI 0xf0200000
|
|
#define THUMB_ORR 0x4300
|
|
#define THUMB2_ORR 0xea400000
|
|
#define THUMB2_ORRI 0xf0400000
|
|
#define THUMB_EOR 0x4040
|
|
#define THUMB2_EOR 0xea800000
|
|
#define THUMB2_EORI 0xf0800000
|
|
#define THUMB_REV 0xba00
|
|
#define THUMB2_REV 0xfa90f080
|
|
#define THUMB_SXTB 0xb240
|
|
#define THUMB2_SXTB 0xfa40f080
|
|
#define THUMB_UXTB 0xb2c0
|
|
#define THUMB2_UXTB 0xfa50f080
|
|
#define THUMB_SXTH 0xb200
|
|
#define THUMB2_SXTH 0xfa00f080
|
|
#define THUMB_UXTH 0xb280
|
|
#define THUMB2_UXTH 0xfa10f080
|
|
#define ARM_LSL 0x00000000
|
|
#define THUMB_LSL 0x4080
|
|
#define THUMB2_LSL 0xfa00f000
|
|
#define THUMB_LSLI 0x0000
|
|
#define THUMB2_LSLI 0xea4f0000
|
|
#define ARM_LSR 0x00000020
|
|
#define THUMB_LSR 0x40c0
|
|
#define THUMB2_LSR 0xfa20f000
|
|
#define THUMB_LSRI 0x0800
|
|
#define THUMB2_LSRI 0xea4f0010
|
|
#define ARM_ASR 0x00000040
|
|
#define THUMB_ASR 0x4100
|
|
#define THUMB2_ASR 0xfa40f000
|
|
#define THUMB_ASRI 0x1000
|
|
#define THUMB2_ASRI 0xea4f0020
|
|
#define THUMB_CMP 0x4280
|
|
#define THUMB_CMPX 0x4500
|
|
#define THUMB2_CMP 0xebb00000
|
|
#define THUMB_CMPI 0x2800
|
|
#define THUMB2_CMPI 0xf1b00000
|
|
#define THUMB2_CMN 0xeb100000
|
|
#define THUMB2_CMNI 0xf1100000
|
|
#define THUMB_TST 0x4200
|
|
#define THUMB2_TST 0xea100000
|
|
#define THUMB2_TSTI 0xf0100000
|
|
#define THUMB_BLX 0x4780
|
|
#define THUMB_BX 0x4700
|
|
#define THUMB_CC_B 0xd000
|
|
#define THUMB_B 0xe000
|
|
#define THUMB2_CC_B 0xf0008000
|
|
#define THUMB2_B 0xf0009000
|
|
#define THUMB2_BLI 0xf000d000
|
|
#define THUMB2_BLXI 0xf000c000
|
|
#define THUMB2_P 0x00000400
|
|
#define THUMB2_U 0x00000200
|
|
#define THUMB_LDRSB 0x5600
|
|
#define THUMB2_LDRSB 0xf9100000
|
|
#define THUMB2_LDRSBI 0xf9100c00
|
|
#define THUMB2_LDRSBWI 0xf9900000
|
|
#define THUMB_LDRB 0x5c00
|
|
#define THUMB2_LDRB 0xf8100000
|
|
#define THUMB_LDRBI 0x7800
|
|
#define THUMB2_LDRBI 0xf8100c00
|
|
#define THUMB2_LDRBWI 0xf8900000
|
|
#define THUMB_LDRSH 0x5e00
|
|
#define THUMB2_LDRSH 0xf9300000
|
|
#define THUMB2_LDRSHI 0xf9300c00
|
|
#define THUMB2_LDRSHWI 0xf9b00000
|
|
#define THUMB_LDRH 0x5a00
|
|
#define THUMB2_LDRH 0xf8300000
|
|
#define THUMB_LDRHI 0x8800
|
|
#define THUMB2_LDRHI 0xf8300c00
|
|
#define THUMB2_LDRHWI 0xf8b00000
|
|
#define THUMB_LDR 0x5800
|
|
#define THUMB2_LDR 0xf8500000
|
|
#define THUMB2_LDRP 0xf85f0000
|
|
#define THUMB_LDRI 0x6800
|
|
#define THUMB_LDRISP 0x9800
|
|
#define THUMB2_LDRI 0xf8500c00
|
|
#define THUMB2_LDRWI 0xf8d00000
|
|
#define THUMB_STRB 0x5400
|
|
#define THUMB2_STRB 0xf8000000
|
|
#define THUMB_STRBI 0x7000
|
|
#define THUMB2_STRBI 0xf8000c00
|
|
#define THUMB2_STRBWI 0xf8800000
|
|
#define THUMB_STRH 0x5200
|
|
#define THUMB2_STRH 0xf8200000
|
|
#define THUMB_STRHI 0x8000
|
|
#define THUMB2_STRHI 0xf8200c00
|
|
#define THUMB2_STRHWI 0xf8a00000
|
|
#define THUMB_STR 0x5000
|
|
#define THUMB2_STR 0xf8400000
|
|
#define THUMB_STRI 0x6000
|
|
#define THUMB2_STRWI 0xf8c00000
|
|
#define THUMB_STRISP 0x9000
|
|
#define THUMB2_STRI 0xf8400c00
|
|
#define THUMB2_LDM_W 0x00200000
|
|
#define THUMB2_PUSH 0xe92d0000
|
|
#define THUMB_DMB 0xf3bf8f50
|
|
#define THUMB_LDREX 0xe8500f00
|
|
#define THUMB_STREX 0xe8400000
|
|
#define THUMB_BRK 0xbe00
|
|
|
|
#define _NOREG (jit_gpr_regno(_PC))
|
|
|
|
#define JIT_RELOC_B JIT_RELOC_FLAG_0
|
|
|
|
static void
|
|
emit_wide_thumb(jit_state_t *_jit, uint32_t inst)
|
|
{
|
|
emit_u16(_jit, inst >> 16);
|
|
emit_u16_with_pool(_jit, inst & 0xffff);
|
|
}
|
|
|
|
static uint32_t
|
|
rotate_left(uint32_t v, uint32_t n) {
|
|
if (n == 0) {
|
|
return v;
|
|
}
|
|
ASSERT(n < 32);
|
|
return (v << n | v >> (32 - n));
|
|
}
|
|
|
|
static int
|
|
encode_arm_immediate(unsigned int v)
|
|
{
|
|
unsigned int a, i;
|
|
|
|
for (i = 0; i < 32; i += 2)
|
|
if ((a = rotate_left(v, i)) <= 0xff)
|
|
return (a | (i << 7));
|
|
|
|
return (-1);
|
|
}
|
|
|
|
static int
|
|
encode_thumb_immediate(unsigned int v)
|
|
{
|
|
int i;
|
|
unsigned int m;
|
|
unsigned int n;
|
|
/* 00000000 00000000 00000000 abcdefgh */
|
|
if ((v & 0xff) == v)
|
|
return (v);
|
|
/* 00000000 abcdefgh 00000000 abcdefgh */
|
|
if ((v & 0xff00ff) == v && ((v & 0xff0000) >> 16) == (v & 0xff))
|
|
return ((v & 0xff) | (1 << 12));
|
|
/* abcdefgh 00000000 abcdefgh 00000000 */
|
|
if (((v & 0xffff0000) >> 16) == (v & 0xffff) && (v & 0xff) == 0)
|
|
return (((v & 0x0000ff00) >> 8) | (2 << 12));
|
|
/* abcdefgh abcdefgh abcdefgh abcdefgh */
|
|
if ( (v & 0xff) == ((v & 0xff00) >> 8) &&
|
|
((v & 0xff00) >> 8) == ((v & 0xff0000) >> 16) &&
|
|
((v & 0xff0000) << 8) == (v & 0xff000000))
|
|
return ((v & 0xff) | (3 << 12));
|
|
/* 1bcdefgh << 24 ... 1bcdefgh << 1 */
|
|
for (i = 8, m = 0xff000000, n = 0x80000000;
|
|
i < 23; i++, m >>= 1, n >>= 1) {
|
|
if ((v & m) == v && (v & n)) {
|
|
v >>= 32 - i;
|
|
if (!(i & 1))
|
|
v &= 0x7f;
|
|
i >>= 1;
|
|
return (((i & 7) << 12) | ((i & 8) << 23) | v);
|
|
}
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
static int
|
|
encode_thumb_word_immediate(unsigned int v)
|
|
{
|
|
if ((v & 0xfffff000) == 0)
|
|
return (((v & 0x800) << 15) | ((v & 0x700) << 4) | (v & 0xff));
|
|
return (-1);
|
|
}
|
|
|
|
static uint32_t
|
|
read_wide_thumb(uint32_t *loc)
|
|
{
|
|
uint16_t *sloc = (uint16_t*)loc;
|
|
return (sloc[0] << 16) | sloc[1];
|
|
}
|
|
|
|
static void
|
|
write_wide_thumb(uint32_t *loc, uint32_t v)
|
|
{
|
|
uint16_t *sloc = (uint16_t *)loc;
|
|
sloc[0] = v >> 16;
|
|
sloc[1] = v & 0xffff;
|
|
}
|
|
|
|
static int
|
|
offset_in_jmp_range(int32_t offset, int flags)
|
|
{
|
|
if (!(offset & 1) && flags | JIT_RELOC_B)
|
|
return 0;
|
|
else
|
|
return -0x1000000 <= offset && offset <= 0xffffff;
|
|
}
|
|
|
|
static int32_t
|
|
decode_thumb_jump(uint32_t v)
|
|
{
|
|
uint32_t s = (v >> 26) & 1;
|
|
uint32_t j1 = (v >> 13) & 1;
|
|
uint32_t j2 = (v >> 11) & 1;
|
|
uint32_t i1 = s ? j1 : !j1;
|
|
uint32_t i2 = s ? j2 : !j2;
|
|
uint32_t hi = (v >> 16) & 0x3ff;
|
|
uint32_t lo = v & 0x7ff;
|
|
|
|
int32_t ret = s << 31;
|
|
ret >>= 8;
|
|
ret |= i1 << 22;
|
|
ret |= i2 << 21;
|
|
ret |= hi << 11;
|
|
ret |= lo;
|
|
return ret << 1;
|
|
}
|
|
|
|
static const uint32_t thumb_jump_mask = 0xf800d000;
|
|
|
|
static uint32_t
|
|
encode_thumb_jump(int32_t v)
|
|
{
|
|
ASSERT(offset_in_jmp_range(v, 0));
|
|
v >>= 1;
|
|
uint32_t s = !!(v & 0x800000);
|
|
uint32_t i1 = !!(v & 0x400000);
|
|
uint32_t i2 = !!(v & 0x200000);
|
|
uint32_t j1 = s ? i1 : !i1;
|
|
uint32_t j2 = s ? i2 : !i2;
|
|
uint32_t ret = (s<<26)|((v&0x1ff800)<<5)|(j1<<13)|(j2<<11)|(v&0x7ff);
|
|
ASSERT(decode_thumb_jump(ret) == v << 1);
|
|
ASSERT((ret & thumb_jump_mask) == 0);
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
patch_thumb_jump(uint32_t inst, int32_t v)
|
|
{
|
|
inst &= thumb_jump_mask;
|
|
if (!(v & 1)) {
|
|
ASSERT(inst == THUMB2_BLI || inst == THUMB2_BLXI);
|
|
v = (v + 2) & ~2;
|
|
inst = THUMB2_BLXI;
|
|
}
|
|
return inst | encode_thumb_jump(v);
|
|
}
|
|
|
|
static int32_t
|
|
read_jmp_offset(uint32_t *loc)
|
|
{
|
|
return decode_thumb_jump(read_wide_thumb(loc));
|
|
}
|
|
|
|
static void
|
|
patch_jmp_offset(uint32_t *loc, int32_t v)
|
|
{
|
|
write_wide_thumb(loc, patch_thumb_jump(read_wide_thumb(loc), v));
|
|
}
|
|
|
|
static void
|
|
patch_veneer_jmp_offset(uint32_t *loc, int32_t v)
|
|
{
|
|
ASSERT(!(v & 1));
|
|
patch_jmp_offset(loc, v | 1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
emit_thumb_jump(jit_state_t *_jit, uint32_t inst)
|
|
{
|
|
while (1) {
|
|
uint8_t *pc_base = _jit->pc.uc + 4;
|
|
int32_t off = (uint8_t*)jit_address(_jit) - pc_base;
|
|
enum jit_reloc_kind kind = JIT_RELOC_JMP_WITH_VENEER;
|
|
if (inst == THUMB2_B)
|
|
kind |= JIT_RELOC_B;
|
|
jit_reloc_t ret = jit_reloc (_jit, kind, 0, _jit->pc.uc, pc_base, 0);
|
|
uint8_t thumb_jump_width = 24;
|
|
if (add_pending_literal(_jit, ret, thumb_jump_width - 1)) {
|
|
emit_wide_thumb(_jit, patch_thumb_jump(inst, off));
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
offset_in_jcc_range(int32_t v, int flags)
|
|
{
|
|
if (!(v & 1))
|
|
return 0;
|
|
else
|
|
return -0x100000 <= v && v <= 0xfffff;
|
|
}
|
|
|
|
static int32_t
|
|
decode_thumb_cc_jump(uint32_t v)
|
|
{
|
|
uint32_t s = (v >> 26) & 1;
|
|
uint32_t j1 = (v >> 13) & 1;
|
|
uint32_t j2 = (v >> 11) & 1;
|
|
uint32_t hi = (v >> 16) & 0x3f;
|
|
uint32_t lo = v & 0x7ff;
|
|
|
|
int32_t ret = s << 31;
|
|
ret >>= 12;
|
|
ret |= j2 << 18;
|
|
ret |= j1 << 17;
|
|
ret |= hi << 11;
|
|
ret |= lo;
|
|
return ret << 1;
|
|
}
|
|
|
|
static const uint32_t thumb_cc_jump_mask = 0xfbc0d000;
|
|
|
|
static uint32_t
|
|
encode_thumb_cc_jump(int32_t v)
|
|
{
|
|
ASSERT(offset_in_jcc_range(v, 0));
|
|
v >>= 1;
|
|
uint32_t s = !!(v & 0x80000);
|
|
uint32_t j2 = !!(v & 0x40000);
|
|
uint32_t j1 = !!(v & 0x20000);
|
|
uint32_t hi = (v >> 11) & 0x3f;
|
|
uint32_t lo = v & 0x7ff;
|
|
uint32_t ret = (s<<26)|(hi << 16)|(j1<<13)|(j2<<11)|lo;
|
|
ASSERT(decode_thumb_cc_jump(ret) == v << 1);
|
|
ASSERT((ret & thumb_cc_jump_mask) == 0);
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
patch_thumb_cc_jump(uint32_t inst, int32_t v)
|
|
{
|
|
return (inst & thumb_cc_jump_mask) | encode_thumb_cc_jump(v);
|
|
}
|
|
|
|
static int32_t
|
|
read_jcc_offset(uint32_t *loc)
|
|
{
|
|
return decode_thumb_cc_jump(read_wide_thumb(loc));
|
|
}
|
|
|
|
static void
|
|
patch_jcc_offset(uint32_t *loc, int32_t v)
|
|
{
|
|
write_wide_thumb(loc, patch_thumb_cc_jump(read_wide_thumb(loc), v));
|
|
}
|
|
|
|
static void
|
|
patch_veneer_jcc_offset(uint32_t *loc, int32_t v)
|
|
{
|
|
ASSERT(!(v & 1));
|
|
patch_jcc_offset(loc, v | 1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
emit_thumb_cc_jump(jit_state_t *_jit, uint32_t inst)
|
|
{
|
|
while (1) {
|
|
uint8_t *pc_base = _jit->pc.uc + 4;
|
|
int32_t off = (uint8_t*)jit_address(_jit) - pc_base;
|
|
jit_reloc_t ret =
|
|
jit_reloc (_jit, JIT_RELOC_JCC_WITH_VENEER, 0, _jit->pc.uc, pc_base, 0);
|
|
uint8_t thumb_cc_jump_width = 20;
|
|
if (add_pending_literal(_jit, ret, thumb_cc_jump_width - 1)) {
|
|
emit_wide_thumb(_jit, patch_thumb_cc_jump(inst, off));
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
torrr(jit_state_t *_jit, int o, int rn, int rd, int rm)
|
|
{
|
|
ASSERT(!(o & 0xf0f0f));
|
|
emit_wide_thumb(_jit, o|(_u4(rn)<<16)|(_u4(rd)<<8)|_u4(rm));
|
|
}
|
|
|
|
static void
|
|
torxr(jit_state_t *_jit, int o, int rn, int rt, int rm)
|
|
{
|
|
ASSERT(!(o & 0xf0f0f));
|
|
emit_wide_thumb(_jit, o|(_u4(rn)<<16)|(_u4(rt)<<12)|_u4(rm));
|
|
}
|
|
|
|
static void
|
|
torrrr(jit_state_t *_jit, int o, int rn, int rl, int rh, int rm)
|
|
{
|
|
ASSERT(!(o & 0x000fff0f));
|
|
emit_wide_thumb(_jit, o|(_u4(rn)<<16)|(_u4(rl)<<12)|(_u4(rh)<<8)|_u4(rm));
|
|
}
|
|
|
|
static void
|
|
torri(jit_state_t *_jit, int o, int rn, int rd, int im)
|
|
{
|
|
ASSERT(!(o & 0x0c0f7fff));
|
|
ASSERT(!(im & 0xfbff8f00));
|
|
emit_wide_thumb(_jit, o|(_u4(rn)<<16)|(_u4(rd)<<8)|im);
|
|
}
|
|
|
|
static void
|
|
torri8(jit_state_t *_jit, int o, int rn, int rt, int im)
|
|
{
|
|
ASSERT(!(o & 0x000ff0ff));
|
|
ASSERT(!(im & 0xffffff00));
|
|
emit_wide_thumb(_jit, o|(_u4(rn)<<16)|(_u4(rt)<<12)|im);
|
|
}
|
|
|
|
static void
|
|
torri12(jit_state_t *_jit, int o, int rn, int rt, int im)
|
|
{
|
|
ASSERT(!(o & 0x000fffff));
|
|
ASSERT(!(im & 0xfffff000));
|
|
emit_wide_thumb(_jit, o|(_u4(rn)<<16)|(_u4(rt)<<12)|im);
|
|
}
|
|
|
|
static void
|
|
tshift(jit_state_t *_jit, int o, int rd, int rm, int im)
|
|
{
|
|
ASSERT(!(o & 0x7fcf));
|
|
ASSERT(im >= 0 && im < 32);
|
|
emit_wide_thumb(_jit, o|((im&0x1c)<<10)|(_u4(rd)<<8)|((im&3)<<6)|_u4(rm));
|
|
}
|
|
|
|
static void
|
|
toriw(jit_state_t *_jit, int o, int rd, int im)
|
|
{
|
|
ASSERT(!(im & 0xffff0000));
|
|
emit_wide_thumb(_jit, o|((im&0xf000)<<4)|((im&0x800)<<15)|((im&0x700)<<4)|(_u4(rd)<<8)|(im&0xff));
|
|
}
|
|
|
|
static jit_reloc_t
|
|
tcb(jit_state_t *_jit, int cc)
|
|
{
|
|
ASSERT(!(cc & 0xfffffff));
|
|
ASSERT(cc != ARM_CC_AL && cc != ARM_CC_NV);
|
|
cc = ((uint32_t)cc) >> 6;
|
|
return emit_thumb_cc_jump(_jit, THUMB2_CC_B|cc);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
tb(jit_state_t *_jit, int o)
|
|
{
|
|
ASSERT(!(o & 0x07ff2fff));
|
|
return emit_thumb_jump(_jit, o);
|
|
}
|
|
|
|
static void
|
|
T1_ORR(jit_state_t *_jit, int32_t rdn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_ORR|(_u3(rm)<<3)|_u3(rdn));
|
|
}
|
|
|
|
static void
|
|
T2_ORR(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_ORR,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T2_ORRI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_ORRI,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T1_EOR(jit_state_t *_jit, int32_t rdn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_EOR|(_u3(rm)<<3)|_u3(rdn));
|
|
}
|
|
|
|
static void
|
|
T2_EOR(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_EOR,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T2_EORI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_EORI,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T1_MOV(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_MOV|((_u4(rd)&8)<<4)|(_u4(rm)<<3)|(rd&7));
|
|
}
|
|
|
|
static void
|
|
T1_MOVI(jit_state_t *_jit, int32_t rd, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_MOVI|(_u3(rd)<<8)|_u8(im));
|
|
}
|
|
|
|
static void
|
|
T2_MOVI(jit_state_t *_jit, int32_t rd, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_MOVI,_NOREG,rd,im);
|
|
}
|
|
|
|
static void
|
|
T2_MOVWI(jit_state_t *_jit, int32_t rd, int32_t im)
|
|
{
|
|
return toriw(_jit, THUMB2_MOVWI,rd,im);
|
|
}
|
|
|
|
static void
|
|
T2_MOVTI(jit_state_t *_jit, int32_t rd, int32_t im)
|
|
{
|
|
return toriw(_jit, THUMB2_MOVTI,rd,im);
|
|
}
|
|
|
|
static void
|
|
T1_MVN(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_MVN|(_u3(rm)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T2_MVN(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_MVN,_NOREG,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T2_MVNI(jit_state_t *_jit, int32_t rd, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_MVNI,_NOREG,rd,im);
|
|
}
|
|
|
|
static void
|
|
T1_NOT(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
return T1_MVN(_jit, rd,rm);
|
|
}
|
|
|
|
static void
|
|
T2_NOT(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
return T2_MVN(_jit, rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_NOP(jit_state_t *_jit)
|
|
{
|
|
emit_u16_with_pool(_jit, 0xbf00);
|
|
}
|
|
|
|
static void
|
|
T1_ADD(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_ADD|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T1_ADDX(jit_state_t *_jit, int32_t rdn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_ADDX|((_u4(rdn)&8)<<4)|(_u4(rm)<<3)|(rdn&7));
|
|
}
|
|
|
|
static void
|
|
T2_ADD(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_ADD,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_ADDI3(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_ADDI3|(_u3(im)<<6)|(_u3(rn)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T1_ADDI8(jit_state_t *_jit, int32_t rdn, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_ADDI8|(_u3(rdn)<<8)|_u8(im));
|
|
}
|
|
|
|
static void
|
|
T2_ADDI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_ADDI,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T2_ADDWI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_ADDWI,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T2_ADDS(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_ADD|ARM_S,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T2_ADDSI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_ADDI|ARM_S,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T1_ADC(jit_state_t *_jit, int32_t rdn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_ADC|(_u3(rm)<<3)|_u3(rdn));
|
|
}
|
|
|
|
static void
|
|
T2_ADCS(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_ADC|ARM_S,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T2_ADCSI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_ADCI|ARM_S,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T1_SUB(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_SUB|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T2_SUB(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_SUB,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_SUBI3(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_SUBI3|(_u3(im)<<6)|(_u3(rn)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T1_SUBI8(jit_state_t *_jit, int32_t rdn, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_SUBI8|(_u3(rdn)<<8)|_u8(im));
|
|
}
|
|
|
|
static void
|
|
T2_SUBI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_SUBI,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T2_SUBWI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_SUBWI,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T2_SUBS(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_SUB|ARM_S,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T2_SUBSI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_SUBI|ARM_S,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T1_SBC(jit_state_t *_jit, int32_t rdn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_SBC|(_u3(rm)<<3)|_u3(rdn));
|
|
}
|
|
|
|
static void
|
|
T2_SBCS(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_SBC|ARM_S,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T2_SBCSI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_SBCI|ARM_S,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T1_RSBI(jit_state_t *_jit, int32_t rd, int32_t rn)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_RSBI|(_u3(rn)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T2_RSBI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_RSBI,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T1_MUL(jit_state_t *_jit, int32_t rdm, int32_t rn)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_MUL|(_u3(rn)<<3)|_u3(rdm));
|
|
}
|
|
|
|
static void
|
|
T2_MUL(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_MUL,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T2_SMULL(jit_state_t *_jit, int32_t rl, int32_t rh, int32_t rn, int32_t rm)
|
|
{
|
|
return torrrr(_jit, THUMB2_SMULL,rn,rl,rh,rm);
|
|
}
|
|
|
|
static void
|
|
T2_UMULL(jit_state_t *_jit, int32_t rl, int32_t rh, int32_t rn, int32_t rm)
|
|
{
|
|
return torrrr(_jit, THUMB2_UMULL,rn,rl,rh,rm);
|
|
}
|
|
|
|
static void
|
|
T2_SDIV(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_SDIV,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T2_UDIV(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_UDIV,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_MLS(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm, int32_t ra)
|
|
{
|
|
return torrrr(_jit, THUMB_MLS, rn, ra, rd, rm);
|
|
}
|
|
|
|
static void
|
|
T1_AND(jit_state_t *_jit, int32_t rdn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_AND|(_u3(rm)<<3)|_u3(rdn));
|
|
}
|
|
|
|
static void
|
|
T2_AND(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_AND,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T2_ANDI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_ANDI,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T2_BICI(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_BICI,rn,rd,im);
|
|
}
|
|
|
|
static void
|
|
T1_REV(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_REV|(_u3(rm)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T2_REV(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_REV,rm,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_SXTB(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_SXTB|(_u3(rm)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T2_SXTB(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_SXTB,_NOREG,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_UXTB(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_UXTB|(_u3(rm)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T2_UXTB(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_UXTB,_NOREG,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_SXTH(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_SXTH|(_u3(rm)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T2_SXTH(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_SXTH,_NOREG,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_UXTH(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_UXTH|(_u3(rm)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T2_UXTH(jit_state_t *_jit, int32_t rd, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_UXTH,_NOREG,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_LSL(jit_state_t *_jit, int32_t rdn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LSL|(_u3(rm)<<3)|_u3(rdn));
|
|
}
|
|
|
|
static void
|
|
T2_LSL(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_LSL,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_LSLI(jit_state_t *_jit, int32_t rd, int32_t rm, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LSLI|(_u5(im)<<6)|(_u3(rm)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T2_LSLI(jit_state_t *_jit, int32_t rd, int32_t rm, int32_t im)
|
|
{
|
|
return tshift(_jit, THUMB2_LSLI,rd,rm,im);
|
|
}
|
|
|
|
static void
|
|
T1_LSR(jit_state_t *_jit, int32_t rdn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LSR|(_u3(rm)<<3)|_u3(rdn));
|
|
}
|
|
|
|
static void
|
|
T2_LSR(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_LSR,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_LSRI(jit_state_t *_jit, int32_t rd, int32_t rm, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LSRI|(_u5(im)<<6)|(_u3(rm)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T2_LSRI(jit_state_t *_jit, int32_t rd, int32_t rm, int32_t im)
|
|
{
|
|
return tshift(_jit, THUMB2_LSRI,rd,rm,im);
|
|
}
|
|
|
|
static void
|
|
T1_ASR(jit_state_t *_jit, int32_t rdn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_ASR|(_u3(rm)<<3)|_u3(rdn));
|
|
}
|
|
|
|
static void
|
|
T2_ASR(jit_state_t *_jit, int32_t rd, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_ASR,rn,rd,rm);
|
|
}
|
|
|
|
static void
|
|
T1_ASRI(jit_state_t *_jit, int32_t rd, int32_t rm, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_ASRI|(_u5(im)<<6)|(_u3(rm)<<3)|_u3(rd));
|
|
}
|
|
|
|
static void
|
|
T2_ASRI(jit_state_t *_jit, int32_t rd, int32_t rm, int32_t im)
|
|
{
|
|
return tshift(_jit, THUMB2_ASRI,rd,rm,im);
|
|
}
|
|
|
|
static void
|
|
T1_CMP(jit_state_t *_jit, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_CMP|(_u3(rm)<<3)|_u3(rn));
|
|
}
|
|
|
|
static void
|
|
T1_CMPX(jit_state_t *_jit, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_CMPX|((_u4(rn)&8)<<4)|(_u4(rm)<<3)|(rn&7));
|
|
}
|
|
|
|
static void
|
|
T2_CMP(jit_state_t *_jit, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_CMP,rn,_NOREG,rm);
|
|
}
|
|
|
|
static void
|
|
T1_CMPI(jit_state_t *_jit, int32_t rn, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_CMPI|(_u3(rn)<<8)|_u8(im));
|
|
}
|
|
|
|
static void
|
|
T2_CMPI(jit_state_t *_jit, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_CMPI,rn,_NOREG,im);
|
|
}
|
|
|
|
static void
|
|
T2_CMNI(jit_state_t *_jit, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_CMNI,rn,_NOREG,im);
|
|
}
|
|
|
|
static void
|
|
T1_TST(jit_state_t *_jit, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_TST|(_u3(rm)<<3)|_u3(rn));
|
|
}
|
|
|
|
static void
|
|
T2_TST(jit_state_t *_jit, int32_t rn, int32_t rm)
|
|
{
|
|
return torrr(_jit, THUMB2_TST,rn,_NOREG,rm);
|
|
}
|
|
|
|
static void
|
|
T2_TSTI(jit_state_t *_jit, int32_t rn, int32_t im)
|
|
{
|
|
return torri(_jit, THUMB2_TSTI,rn,_NOREG,im);
|
|
}
|
|
|
|
static void
|
|
T1_BLX(jit_state_t *_jit, int32_t r0)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_BLX|(_u4(r0)<<3));
|
|
}
|
|
|
|
static void
|
|
T1_BX(jit_state_t *_jit, int32_t r0)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_BX|(_u4(r0)<<3));
|
|
}
|
|
|
|
static jit_reloc_t
|
|
T2_CC_B(jit_state_t *_jit, uint32_t cc)
|
|
{
|
|
return tcb(_jit, cc);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
T2_B(jit_state_t *_jit)
|
|
{
|
|
return tb(_jit, THUMB2_B);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
T2_BLI(jit_state_t *_jit)
|
|
{
|
|
return tb(_jit, THUMB2_BLI);
|
|
}
|
|
|
|
enum dmb_option { DMB_ISH = 0xb };
|
|
static void
|
|
T1_DMB(jit_state_t *_jit, enum dmb_option option)
|
|
{
|
|
emit_wide_thumb(_jit, THUMB_DMB|_u4(option));
|
|
}
|
|
|
|
static void
|
|
T1_LDREX(jit_state_t *_jit, int32_t rt, int32_t rn, int8_t offset)
|
|
{
|
|
emit_wide_thumb(_jit, THUMB_LDREX|(_u4(rn)<<16)|(_u4(rt)<<12)|_u8(offset));
|
|
}
|
|
|
|
static void
|
|
T1_STREX(jit_state_t *_jit, int32_t rd, int32_t rt, int32_t rn, int8_t offset)
|
|
{
|
|
emit_wide_thumb
|
|
(_jit, THUMB_STREX|(_u4(rn)<<16)|(_u4(rt)<<12)|(_u4(rd)<<8)|_u8(offset));
|
|
}
|
|
|
|
static void
|
|
T1_LDRSB(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LDRSB|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_LDRSB(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
return torxr(_jit, THUMB2_LDRSB,rn,rt,rm);
|
|
}
|
|
|
|
static void
|
|
T2_LDRSBI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_LDRSBI|THUMB2_U,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_LDRSBWI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri12(_jit, THUMB2_LDRSBWI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_LDRSBIN(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_LDRSBI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T1_LDRB(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LDRB|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_LDRB(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
return torxr(_jit, THUMB2_LDRB,rn,rt,rm);
|
|
}
|
|
|
|
static void
|
|
T1_LDRBI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LDRBI|(_u5(im)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_LDRBI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_LDRBI|THUMB2_U,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_LDRBWI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri12(_jit, THUMB2_LDRBWI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_LDRBIN(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_LDRBI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T1_LDRSH(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LDRSH|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_LDRSH(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
return torxr(_jit, THUMB2_LDRSH,rn,rt,rm);
|
|
}
|
|
|
|
static void
|
|
T2_LDRSHI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_LDRSHI|THUMB2_U,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_LDRSHWI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri12(_jit, THUMB2_LDRSHWI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_LDRSHIN(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_LDRSHI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T1_LDRH(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LDRH|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_LDRH(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
return torxr(_jit, THUMB2_LDRH,rn,rt,rm);
|
|
}
|
|
|
|
static void
|
|
T1_LDRHI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LDRHI|(_u5(im)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_LDRHI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_LDRHI|THUMB2_U,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_LDRHWI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri12(_jit, THUMB2_LDRHWI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_LDRHIN(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_LDRHI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T1_LDR(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LDR|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_LDR(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
return torxr(_jit, THUMB2_LDR,rn,rt,rm);
|
|
}
|
|
|
|
static void
|
|
T1_LDRI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LDRI|(_u5(im)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T1_LDRISP(jit_state_t *_jit, int32_t rt, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_LDRISP|(_u3(rt)<<8)|_u8(im));
|
|
}
|
|
|
|
static void
|
|
T2_LDRI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_LDRI|THUMB2_U,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_LDRWI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri12(_jit, THUMB2_LDRWI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_LDRIN(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_LDRI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T1_STRB(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_STRB|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_STRB(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
return torxr(_jit, THUMB2_STRB,rn,rt,rm);
|
|
}
|
|
|
|
static void
|
|
T1_STRBI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_STRBI | (_u5(im) << 6) | (_u3(rn) << 3) | _u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_STRBI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_STRBI|THUMB2_U,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_STRBWI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri12(_jit, THUMB2_STRBWI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_STRBIN(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_STRBI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T1_STRH(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_STRH|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_STRH(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
return torxr(_jit, THUMB2_STRH,rn,rt,rm);
|
|
}
|
|
|
|
static void
|
|
T1_STRHI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_STRHI|(_u5(im)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_STRHI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_STRHI|THUMB2_U,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_STRHWI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri12(_jit, THUMB2_STRHWI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_STRHIN(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_STRHI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T1_STR(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_STR|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T2_STR(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t rm)
|
|
{
|
|
return torxr(_jit, THUMB2_STR,rn,rt,rm);
|
|
}
|
|
|
|
static void
|
|
T1_STRI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_STRI|(_u5(im)<<6)|(_u3(rn)<<3)|_u3(rt));
|
|
}
|
|
|
|
static void
|
|
T1_STRISP(jit_state_t *_jit, int32_t rt, int32_t im)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_STRISP|(_u3(rt)<<8)|(_u8(im)));
|
|
}
|
|
|
|
static void
|
|
T2_STRI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_STRI|THUMB2_U,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_STRWI(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri12(_jit, THUMB2_STRWI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T2_STRIN(jit_state_t *_jit, int32_t rt, int32_t rn, int32_t im)
|
|
{
|
|
return torri8(_jit, THUMB2_STRI,rn,rt,im);
|
|
}
|
|
|
|
static void
|
|
T1_BRK(jit_state_t *_jit)
|
|
{
|
|
emit_u16_with_pool(_jit, THUMB_BRK);
|
|
}
|
|
|
|
static void
|
|
nop(jit_state_t *_jit, int32_t i0)
|
|
{
|
|
for (; i0 > 0; i0 -= 2)
|
|
T1_NOP(_jit);
|
|
|
|
ASSERT(i0 == 0);
|
|
}
|
|
|
|
static void
|
|
movr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
if (r0 != r1) {
|
|
T1_MOV(_jit, r0, r1);
|
|
}
|
|
}
|
|
|
|
enum preserve_flags { PRESERVE_FLAGS, FLAGS_UNIMPORTANT };
|
|
|
|
static void
|
|
_movi(jit_state_t *_jit, int32_t r0, jit_word_t i0, enum preserve_flags flags)
|
|
{
|
|
int i;
|
|
|
|
if (flags == PRESERVE_FLAGS && r0 < 8 && !(i0 & 0xffffff80))
|
|
T1_MOVI(_jit, r0, i0);
|
|
else if (r0 < 8 && !(i0 & 0xffffff80))
|
|
T1_MOVI(_jit, r0, i0);
|
|
else if ((i = encode_thumb_immediate(i0)) != -1)
|
|
T2_MOVI(_jit, r0, i);
|
|
else if ((i = encode_thumb_immediate(~i0)) != -1)
|
|
T2_MVNI(_jit, r0, i);
|
|
else {
|
|
T2_MOVWI(_jit, r0, (uint16_t)i0);
|
|
if (i0 & 0xffff0000)
|
|
T2_MOVTI(_jit, r0, (uint16_t)((unsigned)i0 >> 16));
|
|
}
|
|
}
|
|
|
|
static void
|
|
movi(jit_state_t *_jit, int32_t r0, jit_word_t i0)
|
|
{
|
|
return _movi(_jit, r0, i0, FLAGS_UNIMPORTANT);
|
|
}
|
|
|
|
static int
|
|
offset_in_load_from_pool_range(int32_t offset)
|
|
{
|
|
return -0xfff <= offset && offset <= 0xfff;
|
|
}
|
|
|
|
static int32_t
|
|
decode_load_from_pool_offset(uint32_t inst)
|
|
{
|
|
int32_t ret = inst & 0xfff;
|
|
return ((inst >> 23) & 1) ? ret : -ret;
|
|
}
|
|
|
|
static uint32_t
|
|
encode_load_from_pool_offset(int32_t off)
|
|
{
|
|
ASSERT(offset_in_load_from_pool_range(off));
|
|
uint32_t u = off >= 0;
|
|
uint32_t ret = ((u ? off : -off) & 0xfff) | (u << 23);
|
|
ASSERT(decode_load_from_pool_offset(ret) == off);
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
patch_load_from_pool(uint32_t inst, int32_t off)
|
|
{
|
|
uint32_t load_from_pool_mask = THUMB2_LDRP | (0xf << 12);
|
|
return (inst & load_from_pool_mask) | encode_load_from_pool_offset(off);
|
|
}
|
|
|
|
static int32_t
|
|
read_load_from_pool_offset(uint32_t *loc)
|
|
{
|
|
return decode_load_from_pool_offset(read_wide_thumb(loc));
|
|
}
|
|
|
|
static void
|
|
patch_load_from_pool_offset(uint32_t *loc, int32_t v)
|
|
{
|
|
write_wide_thumb(loc, patch_load_from_pool(read_wide_thumb(loc), v));
|
|
}
|
|
|
|
static jit_reloc_t
|
|
emit_load_from_pool(jit_state_t *_jit, uint32_t inst)
|
|
{
|
|
while (1) {
|
|
uint8_t *pc_base = (uint8_t *)((_jit->pc.w + 4) & ~3);
|
|
uint8_t rsh = 0;
|
|
int32_t off = (_jit->pc.uc - pc_base) >> rsh;
|
|
jit_reloc_t ret =
|
|
jit_reloc (_jit, JIT_RELOC_LOAD_FROM_POOL, 0, _jit->pc.uc, pc_base, rsh);
|
|
uint8_t load_from_pool_width = 12;
|
|
if (add_pending_literal(_jit, ret, load_from_pool_width)) {
|
|
emit_wide_thumb(_jit, patch_load_from_pool(inst, off));
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
static jit_reloc_t
|
|
movi_from_pool(jit_state_t *_jit, int32_t Rt)
|
|
{
|
|
return emit_load_from_pool(_jit, THUMB2_LDRP | (_u4(Rt) << 12));
|
|
}
|
|
|
|
static jit_reloc_t
|
|
mov_addr(jit_state_t *_jit, int32_t r0)
|
|
{
|
|
return movi_from_pool(_jit, r0);
|
|
}
|
|
|
|
static void
|
|
comr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8)
|
|
T1_NOT(_jit, r0, r1);
|
|
else
|
|
T2_NOT(_jit, r0, r1);
|
|
}
|
|
|
|
static void
|
|
negr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8)
|
|
T1_RSBI(_jit, r0, r1);
|
|
else
|
|
T2_RSBI(_jit, r0, r1, 0);
|
|
}
|
|
|
|
static void
|
|
addr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8)
|
|
T1_ADD(_jit, r0, r1, r2);
|
|
else if (r0 == r1 || r0 == r2)
|
|
T1_ADDX(_jit, r0, r0 == r1 ? r2 : r1);
|
|
else
|
|
T2_ADD(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
addi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
int i;
|
|
|
|
if ((r0|r1) < 8 && !(i0 & ~7))
|
|
T1_ADDI3(_jit, r0, r1, i0);
|
|
else if ((r0|r1) < 8 && !(-i0 & ~7))
|
|
T1_SUBI3(_jit, r0, r1, -i0);
|
|
else if (r0 < 8 && r0 == r1 && !(i0 & ~0xff))
|
|
T1_ADDI8(_jit, r0, i0);
|
|
else if (r0 < 8 && r0 == r1 && !(-i0 & ~0xff))
|
|
T1_SUBI8(_jit, r0, -i0);
|
|
else if ((i = encode_thumb_immediate(i0)) != -1)
|
|
T2_ADDI(_jit, r0, r1, i);
|
|
else if ((i = encode_thumb_immediate(-i0)) != -1)
|
|
T2_SUBI(_jit, r0, r1, i);
|
|
else if ((i = encode_thumb_word_immediate(i0)) != -1)
|
|
T2_ADDWI(_jit, r0, r1, i);
|
|
else if ((i = encode_thumb_word_immediate(-i0)) != -1)
|
|
T2_SUBWI(_jit, r0, r1, i);
|
|
else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_ADD(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
addcr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
/* thumb auto set carry if not inside IT block */
|
|
if ((r0|r1|r2) < 8)
|
|
T1_ADD(_jit, r0, r1, r2);
|
|
else
|
|
T2_ADDS(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
addci(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
int i;
|
|
|
|
if ((r0|r1) < 8 && !(i0 & ~7))
|
|
T1_ADDI3(_jit, r0, r1, i0);
|
|
else if ((r0|r1) < 8 && !(-i0 & ~7))
|
|
T1_SUBI3(_jit, r0, r1, -i0);
|
|
else if (r0 < 8 && r0 == r1 && !(i0 & ~0xff))
|
|
T1_ADDI8(_jit, r0, i0);
|
|
else if (r0 < 8 && r0 == r1 && !(-i0 & ~0xff))
|
|
T1_SUBI8(_jit, r0, -i0);
|
|
else if ((i = encode_thumb_immediate(i0)) != -1)
|
|
T2_ADDSI(_jit, r0, r1, i);
|
|
else if ((i = encode_thumb_immediate(-i0)) != -1)
|
|
T2_SUBSI(_jit, r0, r1, i);
|
|
else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_ADDS(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
addxr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
/* keep setting carry because don't know last ADC */
|
|
|
|
/* thumb auto set carry if not inside IT block */
|
|
if ((r0|r1|r2) < 8 && (r0 == r1 || r0 == r2))
|
|
T1_ADC(_jit, r0, r0 == r1 ? r2 : r1);
|
|
else
|
|
T2_ADCS(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
addxi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
int i;
|
|
if ((i = encode_thumb_immediate(i0)) != -1)
|
|
T2_ADCSI(_jit, r0, r1, i);
|
|
else if ((i = encode_thumb_immediate(-i0)) != -1)
|
|
T2_SBCSI(_jit, r0, r1, i);
|
|
else if (r0 != r1) {
|
|
_movi(_jit, r0, i0, PRESERVE_FLAGS);
|
|
T2_ADCS(_jit, r0, r1, r0);
|
|
} else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
_movi(_jit, jit_gpr_regno(reg), i0, PRESERVE_FLAGS);
|
|
T2_ADCS(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
subr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8)
|
|
T1_SUB(_jit, r0, r1, r2);
|
|
else
|
|
T2_SUB(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
subi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
int i;
|
|
|
|
if ((r0|r1) < 8 && !(i0 & ~7))
|
|
T1_SUBI3(_jit, r0, r1, i0);
|
|
else if ((r0|r1) < 8 && !(-i0 & ~7))
|
|
T1_ADDI3(_jit, r0, r1, -i0);
|
|
else if (r0 < 8 && r0 == r1 && !(i0 & ~0xff))
|
|
T1_SUBI8(_jit, r0, i0);
|
|
else if (r0 < 8 && r0 == r1 && !(-i0 & ~0xff))
|
|
T1_ADDI8(_jit, r0, -i0);
|
|
else if ((i = encode_thumb_immediate(i0)) != -1)
|
|
T2_SUBI(_jit, r0, r1, i);
|
|
else if ((i = encode_thumb_immediate(-i0)) != -1)
|
|
T2_ADDI(_jit, r0, r1, i);
|
|
else if ((i = encode_thumb_word_immediate(i0)) != -1)
|
|
T2_SUBWI(_jit, r0, r1, i);
|
|
else if ((i = encode_thumb_word_immediate(-i0)) != -1)
|
|
T2_ADDWI(_jit, r0, r1, i);
|
|
else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_SUB(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
subcr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
/* thumb auto set carry if not inside IT block */
|
|
if ((r0|r1|r2) < 8)
|
|
T1_SUB(_jit, r0, r1, r2);
|
|
else
|
|
T2_SUBS(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
subci(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
int i;
|
|
|
|
if ((r0|r1) < 8 && !(i0 & ~7))
|
|
T1_SUBI3(_jit, r0, r1, i0);
|
|
else if ((r0|r1) < 8 && !(-i0 & ~7))
|
|
T1_ADDI3(_jit, r0, r1, -i0);
|
|
else if (r0 < 8 && r0 == r1 && !(i0 & ~0xff))
|
|
T1_SUBI8(_jit, r0, i0);
|
|
else if (r0 < 8 && r0 == r1 && !(-i0 & ~0xff))
|
|
T1_ADDI8(_jit, r0, -i0);
|
|
else if ((i = encode_thumb_immediate(i0)) != -1)
|
|
T2_SUBSI(_jit, r0, r1, i);
|
|
else if ((i = encode_thumb_immediate(-i0)) != -1)
|
|
T2_ADDSI(_jit, r0, r1, i);
|
|
else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_SUBS(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
subxr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
/* keep setting carry because don't know last SBC */
|
|
|
|
/* thumb auto set carry if not inside IT block */
|
|
if ((r0|r1|r2) < 8 && r0 == r1)
|
|
T1_SBC(_jit, r0, r2);
|
|
else
|
|
T2_SBCS(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
subxi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
int i;
|
|
if ((i = encode_arm_immediate(i0)) != -1)
|
|
T2_SBCSI(_jit, r0, r1, i);
|
|
else if ((i = encode_arm_immediate(-i0)) != -1)
|
|
T2_ADCSI(_jit, r0, r1, i);
|
|
else if (r0 != r1) {
|
|
_movi(_jit, r0, i0, PRESERVE_FLAGS);
|
|
T2_SBCS(_jit, r0, r1, r0);
|
|
} else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
_movi(_jit, jit_gpr_regno(reg), i0, PRESERVE_FLAGS);
|
|
T2_SBCS(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
mulr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if (r0 == r2 && (r0|r1) < 8)
|
|
T1_MUL(_jit, r0, r1);
|
|
else if (r0 == r1 && (r0|r2) < 8)
|
|
T1_MUL(_jit, r0, r2);
|
|
else
|
|
T2_MUL(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
muli(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
mulr(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
iqmulr(jit_state_t *_jit, int32_t r0, int32_t r1,
|
|
int32_t r2, int32_t r3, jit_bool_t sign)
|
|
{
|
|
if (r2 == r3) {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movr(_jit, jit_gpr_regno(reg), r2);
|
|
if (sign)
|
|
T2_SMULL(_jit, r0, r1, jit_gpr_regno(reg), r2);
|
|
else
|
|
T2_UMULL(_jit, r0, r1, jit_gpr_regno(reg), r2);
|
|
unget_temp_gpr(_jit);
|
|
} else if (r0 != r2 && r1 != r2) {
|
|
if (sign)
|
|
T2_SMULL(_jit, r0, r1, r2, r3);
|
|
else
|
|
T2_UMULL(_jit, r0, r1, r2, r3);
|
|
} else {
|
|
if (sign)
|
|
T2_SMULL(_jit, r0, r1, r3, r2);
|
|
else
|
|
T2_UMULL(_jit, r0, r1, r3, r2);
|
|
}
|
|
}
|
|
|
|
static void
|
|
iqmuli(jit_state_t *_jit, int32_t r0, int32_t r1,
|
|
int32_t r2, jit_word_t i0, jit_bool_t sign)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
iqmulr(_jit, r0, r1, r2, jit_gpr_regno(reg), sign);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
qmulr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t r3)
|
|
{
|
|
return iqmulr(_jit, r0,r1,r2,r3,1);
|
|
}
|
|
|
|
static void
|
|
qmulr_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t r3)
|
|
{
|
|
return iqmulr(_jit, r0,r1,r2,r3,0);
|
|
}
|
|
|
|
static void
|
|
qmuli(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t i0)
|
|
{
|
|
return iqmuli(_jit, r0,r1,r2,i0,1);
|
|
}
|
|
|
|
static void
|
|
qmuli_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t i0)
|
|
{
|
|
return iqmuli(_jit, r0,r1,r2,i0,0);
|
|
}
|
|
|
|
static void
|
|
divr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
T2_SDIV(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
divi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
divr(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
divr_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
T2_UDIV(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
divi_u(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
divr_u(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
iqdivr(jit_state_t *_jit, int32_t r0, int32_t r1,
|
|
int32_t r2, int32_t r3, jit_bool_t sign)
|
|
{
|
|
int need_tmp = r0 == r2 || r0 == r3;
|
|
if (need_tmp) {
|
|
int32_t tmp = jit_gpr_regno(get_temp_gpr(_jit));
|
|
if (r0 == r2) {
|
|
movr(_jit, tmp, r2);
|
|
r2 = tmp;
|
|
}
|
|
if (r0 == r3) {
|
|
if (r2 != r3)
|
|
movr(_jit, tmp, r3);
|
|
r3 = tmp;
|
|
}
|
|
}
|
|
if (sign)
|
|
divr(_jit, r0, r2, r3);
|
|
else
|
|
divr_u(_jit, r0, r2, r3);
|
|
T1_MLS(_jit, r1, r3, r0, r2);
|
|
if (need_tmp)
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
iqdivi(jit_state_t *_jit, int32_t r0, int32_t r1,
|
|
int32_t r2, jit_word_t i0, jit_bool_t sign)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
iqdivr(_jit, r0, r1, r2, jit_gpr_regno(reg), sign);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
qdivr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t r3)
|
|
{
|
|
return iqdivr(_jit, r0,r1,r2,r3,1);
|
|
}
|
|
|
|
static void
|
|
qdivr_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t r3)
|
|
{
|
|
return iqdivr(_jit, r0,r1,r2,r3,0);
|
|
}
|
|
|
|
static void
|
|
qdivi(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t i0)
|
|
{
|
|
return iqdivi(_jit, r0,r1,r2,i0,1);
|
|
}
|
|
|
|
static void
|
|
qdivi_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t i0)
|
|
{
|
|
return iqdivi(_jit, r0,r1,r2,i0,0);
|
|
}
|
|
|
|
static void
|
|
iremr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, jit_bool_t sign)
|
|
{
|
|
return iqdivr(_jit, r0, r0, r1, r2, sign);
|
|
}
|
|
|
|
static void
|
|
remr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
return iremr(_jit, r0, r1, r2, 1);
|
|
}
|
|
|
|
static void
|
|
remi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
remr(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
remr_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
return iremr(_jit, r0, r1, r2, 0);
|
|
}
|
|
|
|
static void
|
|
remi_u(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
remr_u(_jit, r0, r1,jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
andr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8 && (r0 == r1 || r0 == r2))
|
|
T1_AND(_jit, r0, r0 == r1 ? r2 : r1);
|
|
else
|
|
T2_AND(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
andi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
int i;
|
|
|
|
if ((i = encode_thumb_immediate(i0)) != -1)
|
|
T2_ANDI(_jit, r0, r1, i);
|
|
else if ((i = encode_thumb_immediate(~i0)) != -1)
|
|
T2_BICI(_jit, r0, r1, i);
|
|
else if (r0 != r1) {
|
|
movi(_jit, r0, i0);
|
|
T2_AND(_jit, r0, r1, r0);
|
|
} else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_AND(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
orr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8 && (r0 == r1 || r0 == r2))
|
|
T1_ORR(_jit, r0, r0 == r1 ? r2 : r1);
|
|
else
|
|
T2_ORR(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
ori(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
int i;
|
|
|
|
if ((i = encode_thumb_immediate(i0)) != -1)
|
|
T2_ORRI(_jit, r0, r1, i);
|
|
else if (r0 != r1) {
|
|
movi(_jit, r0, i0);
|
|
T2_ORR(_jit, r0, r1, r0);
|
|
} else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_ORR(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
xorr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8 && (r0 == r1 || r0 == r2))
|
|
T1_EOR(_jit, r0, r0 == r1 ? r2 : r1);
|
|
else
|
|
T2_EOR(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
xori(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
int i;
|
|
|
|
if ((i = encode_thumb_immediate(i0)) != -1)
|
|
T2_EORI(_jit, r0, r1, i);
|
|
else if (r0 != r1) {
|
|
movi(_jit, r0, i0);
|
|
T2_EOR(_jit, r0, r1, r0);
|
|
} else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_EOR(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
lshr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8 && r0 == r1)
|
|
T1_LSL(_jit, r0, r2);
|
|
else
|
|
T2_LSL(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
lshi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
ASSERT(i0 >= 0 && i0 <= 31);
|
|
if (i0 == 0)
|
|
movr(_jit, r0, r1);
|
|
else {
|
|
if ((r0|r1) < 8)
|
|
T1_LSLI(_jit, r0, r1, i0);
|
|
else
|
|
T2_LSLI(_jit, r0, r1, i0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
rshr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8 && r0 == r1)
|
|
T1_ASR(_jit, r0, r2);
|
|
else
|
|
T2_ASR(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
rshi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
ASSERT(i0 >= 0 && i0 <= 31);
|
|
if (i0 == 0)
|
|
movr(_jit, r0, r1);
|
|
else {
|
|
if ((r0|r1) < 8)
|
|
T1_ASRI(_jit, r0, r1, i0);
|
|
else
|
|
T2_ASRI(_jit, r0, r1, i0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
rshr_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8 && r0 == r1)
|
|
T1_LSR(_jit, r0, r2);
|
|
else
|
|
T2_LSR(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
rshi_u(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
ASSERT(i0 >= 0 && i0 <= 31);
|
|
if (i0 == 0)
|
|
movr(_jit, r0, r1);
|
|
else {
|
|
if ((r0|r1) < 8)
|
|
T1_LSRI(_jit, r0, r1, i0);
|
|
else
|
|
T2_LSRI(_jit, r0, r1, i0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
jmpr(jit_state_t *_jit, int32_t r0)
|
|
{
|
|
T1_BX(_jit, r0);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
jmp(jit_state_t *_jit)
|
|
{
|
|
return T2_B(_jit);
|
|
}
|
|
|
|
static void
|
|
jmpi(jit_state_t *_jit, jit_word_t i0)
|
|
{
|
|
return jit_patch_there(_jit, jmp(_jit), (void*)i0);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bccr(jit_state_t *_jit, int cc, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8)
|
|
T1_CMP(_jit, r0, r1);
|
|
else if ((r0&r1) & 8)
|
|
T1_CMPX(_jit, r0, r1);
|
|
else
|
|
T2_CMP(_jit, r0, r1);
|
|
return T2_CC_B(_jit, cc);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bcci(jit_state_t *_jit, int cc, int32_t r0, jit_word_t i1)
|
|
{
|
|
int i;
|
|
if (r0 < 7 && !(i1 & 0xffffff00))
|
|
T1_CMPI(_jit, r0, i1);
|
|
else if ((i = encode_thumb_immediate(i1)) != -1)
|
|
T2_CMPI(_jit, r0, i);
|
|
else if ((i = encode_thumb_immediate(-i1)) != -1)
|
|
T2_CMNI(_jit, r0, i);
|
|
else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i1);
|
|
T2_CMP(_jit, r0, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
return T2_CC_B(_jit, cc);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bltr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bccr(_jit, ARM_CC_LT, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
blti(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bcci(_jit, ARM_CC_LT, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bltr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bccr(_jit, ARM_CC_LO, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
blti_u(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bcci(_jit, ARM_CC_LO, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bler(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bccr(_jit, ARM_CC_LE, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
blei(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bcci(_jit, ARM_CC_LE, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bler_u(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bccr(_jit, ARM_CC_LS, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
blei_u(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bcci(_jit, ARM_CC_LS, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
beqr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bccr(_jit, ARM_CC_EQ, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
beqi(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bcci(_jit, ARM_CC_EQ, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bger(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bccr(_jit, ARM_CC_GE, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bgei(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bcci(_jit, ARM_CC_GE, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bger_u(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bccr(_jit, ARM_CC_HS, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bgei_u(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bcci(_jit, ARM_CC_HS, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bgtr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bccr(_jit, ARM_CC_GT, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bgti(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bcci(_jit, ARM_CC_GT, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bgtr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bccr(_jit, ARM_CC_HI, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bgti_u(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bcci(_jit, ARM_CC_HI, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bner(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bccr(_jit, ARM_CC_NE, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bnei(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bcci(_jit, ARM_CC_NE, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
baddr(jit_state_t *_jit, int cc, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8)
|
|
T1_ADD(_jit, r0, r0, r1);
|
|
else
|
|
T2_ADDS(_jit, r0, r0, r1);
|
|
return T2_CC_B(_jit, cc);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
baddi(jit_state_t *_jit, int cc, int32_t r0, int i1)
|
|
{
|
|
int i;
|
|
if (r0 < 8 && !(i1 & ~7))
|
|
T1_ADDI3(_jit, r0, r0, i1);
|
|
else if (r0 < 8 && !(-i1 & ~7))
|
|
T1_SUBI3(_jit, r0, r0, -i1);
|
|
else if (r0 < 8 && !(i1 & ~0xff))
|
|
T1_ADDI8(_jit, r0, i1);
|
|
else if (r0 < 8 && !(-i1 & ~0xff))
|
|
T1_SUBI8(_jit, r0, -i1);
|
|
else if ((i = encode_thumb_immediate(i1)) != -1)
|
|
T2_ADDSI(_jit, r0, r0, i);
|
|
else if ((i = encode_thumb_immediate(-i1)) != -1)
|
|
T2_SUBSI(_jit, r0, r0, i);
|
|
else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i1);
|
|
T2_ADDS(_jit, r0, r0, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
return T2_CC_B(_jit, cc);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
boaddr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return baddr(_jit, ARM_CC_VS, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
boaddi(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return baddi(_jit, ARM_CC_VS, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
boaddr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return baddr(_jit, ARM_CC_HS, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
boaddi_u(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return baddi(_jit, ARM_CC_HS, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bxaddr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return baddr(_jit, ARM_CC_VC, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bxaddi(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return baddi(_jit, ARM_CC_VC, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bxaddr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return baddr(_jit, ARM_CC_LO, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bxaddi_u(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return baddi(_jit, ARM_CC_LO, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bsubr(jit_state_t *_jit, int cc, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8)
|
|
T1_SUB(_jit, r0, r0, r1);
|
|
else
|
|
T2_SUBS(_jit, r0, r0, r1);
|
|
return T2_CC_B(_jit, cc);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bsubi(jit_state_t *_jit, int cc, int32_t r0, int i1)
|
|
{
|
|
int i;
|
|
if (r0 < 8 && !(i1 & ~7))
|
|
T1_SUBI3(_jit, r0, r0, i1);
|
|
else if (r0 < 8 && !(-i1 & ~7))
|
|
T1_ADDI3(_jit, r0, r0, -i1);
|
|
else if (r0 < 8 && !(i1 & ~0xff))
|
|
T1_SUBI8(_jit, r0, i1);
|
|
else if (r0 < 8 && !(-i1 & ~0xff))
|
|
T1_ADDI8(_jit, r0, -i1);
|
|
else if ((i = encode_thumb_immediate(i1)) != -1)
|
|
T2_SUBSI(_jit, r0, r0, i);
|
|
else if ((i = encode_thumb_immediate(-i1)) != -1)
|
|
T2_SUBSI(_jit, r0, r0, i);
|
|
else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i1);
|
|
T2_SUBS(_jit, r0, r0, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
return T2_CC_B(_jit, cc);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bosubr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bsubr(_jit, ARM_CC_VS, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bosubi(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bsubi(_jit, ARM_CC_VS, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bosubr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bsubr(_jit, ARM_CC_LO, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bosubi_u(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bsubi(_jit, ARM_CC_LO, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bxsubr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bsubr(_jit, ARM_CC_VC, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bxsubi(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bsubi(_jit, ARM_CC_VC, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bxsubr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bsubr(_jit, ARM_CC_HS, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bxsubi_u(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bsubi(_jit, ARM_CC_HS, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bmxr(jit_state_t *_jit, int cc, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8)
|
|
T1_TST(_jit, r0, r1);
|
|
else
|
|
T2_TST(_jit, r0, r1);
|
|
return T2_CC_B(_jit, cc);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bmxi(jit_state_t *_jit, int cc, int32_t r0, jit_word_t i1)
|
|
{
|
|
int i;
|
|
if ((i = encode_thumb_immediate(i1)) != -1)
|
|
T2_TSTI(_jit, r0, i);
|
|
else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i1);
|
|
T2_TST(_jit, r0, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
return T2_CC_B(_jit, cc);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bmsr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bmxr(_jit, ARM_CC_NE, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bmsi(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bmxi(_jit, ARM_CC_NE, r0, i1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bmcr(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
return bmxr(_jit, ARM_CC_EQ, r0, r1);
|
|
}
|
|
|
|
static jit_reloc_t
|
|
bmci(jit_state_t *_jit, int32_t r0, int32_t i1)
|
|
{
|
|
return bmxi(_jit, ARM_CC_EQ, r0, i1);
|
|
}
|
|
|
|
static void
|
|
ldr_c(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
T2_LDRSBI(_jit, r0, r1, 0);
|
|
}
|
|
|
|
static void
|
|
ldi_c(jit_state_t *_jit, int32_t r0, jit_word_t i0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_LDRSBI(_jit, r0, jit_gpr_regno(reg), 0);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
ldxr_c(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8)
|
|
T1_LDRSB(_jit, r0, r1, r2);
|
|
else
|
|
T2_LDRSB(_jit, r0, r1, r2);
|
|
}
|
|
|
|
#define jit_ldrt_strt_p() 0
|
|
|
|
static void
|
|
ldxi_c(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
|
|
if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
|
|
T2_LDRSBI(_jit, r0, r1, i0);
|
|
else if (i0 < 0 && i0 >= -255)
|
|
T2_LDRSBIN(_jit, r0, r1, -i0);
|
|
else if (i0 >= 0 && i0 <= 4095)
|
|
T2_LDRSBWI(_jit, r0, r1, i0);
|
|
else if (r0 != r1) {
|
|
movi(_jit, r0, i0);
|
|
if ((r0|r1) < 8)
|
|
T1_LDRSB(_jit, r0, r1, r0);
|
|
else
|
|
T2_LDRSB(_jit, r0, r1, r0);
|
|
} else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
if ((r0|r1|jit_gpr_regno(reg)) < 8)
|
|
T1_LDRSB(_jit, r0, r1, jit_gpr_regno(reg));
|
|
else
|
|
T2_LDRSB(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
ldr_uc(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
T2_LDRBI(_jit, r0, r1, 0);
|
|
}
|
|
|
|
static void
|
|
ldi_uc(jit_state_t *_jit, int32_t r0, jit_word_t i0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_LDRBI(_jit, r0, jit_gpr_regno(reg), 0);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
ldxr_uc(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8)
|
|
T1_LDRB(_jit, r0, r1, r2);
|
|
else
|
|
T2_LDRB(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
ldxi_uc(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
if ((r0|r1) < 8 && i0 >= 0 && i0 < 0x20)
|
|
T1_LDRBI(_jit, r0, r1, i0);
|
|
else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
|
|
T2_LDRBI(_jit, r0, r1, i0);
|
|
else if (i0 < 0 && i0 >= -255)
|
|
T2_LDRBIN(_jit, r0, r1, -i0);
|
|
else if (i0 >= 0 && i0 <= 4095)
|
|
T2_LDRBWI(_jit, r0, r1, i0);
|
|
else if (r0 != r1) {
|
|
movi(_jit, r0, i0);
|
|
if ((r0|r1) < 8)
|
|
T1_LDRB(_jit, r0, r1, r0);
|
|
else
|
|
T2_LDRB(_jit, r0, r1, r0);
|
|
} else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
if ((r0|r1|jit_gpr_regno(reg)) < 8)
|
|
T1_LDRB(_jit, r0, r1, jit_gpr_regno(reg));
|
|
else
|
|
T2_LDRB(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
ldr_s(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
T2_LDRSHI(_jit, r0, r1, 0);
|
|
}
|
|
|
|
static void
|
|
ldi_s(jit_state_t *_jit, int32_t r0, jit_word_t i0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_LDRSHI(_jit, r0, jit_gpr_regno(reg), 0);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
ldxr_s(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8)
|
|
T1_LDRSH(_jit, r0, r1, r2);
|
|
else
|
|
T2_LDRSH(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
ldxi_s(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
|
|
T2_LDRSHI(_jit, r0, r1, i0);
|
|
else if (i0 < 0 && i0 >= -255)
|
|
T2_LDRSHIN(_jit, r0, r1, -i0);
|
|
else if (i0 >= 0 && i0 <= 4095)
|
|
T2_LDRSHWI(_jit, r0, r1, i0);
|
|
else if (r0 != r1) {
|
|
movi(_jit, r0, i0);
|
|
if ((r0|r1) < 8)
|
|
T1_LDRSH(_jit, r0, r1, r0);
|
|
else
|
|
T2_LDRSH(_jit, r0, r1, r0);
|
|
} else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
if ((r0|r1|jit_gpr_regno(reg)) < 8)
|
|
T1_LDRSH(_jit, r0, r1, jit_gpr_regno(reg));
|
|
else
|
|
T2_LDRSH(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
ldr_us(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
T2_LDRHI(_jit, r0, r1, 0);
|
|
}
|
|
|
|
static void
|
|
ldi_us(jit_state_t *_jit, int32_t r0, jit_word_t i0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_LDRHI(_jit, r0, jit_gpr_regno(reg), 0);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
ldxr_us(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
|
|
if ((r0|r1|r2) < 8)
|
|
T1_LDRH(_jit, r0, r1, r2);
|
|
else
|
|
T2_LDRH(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
ldxi_us(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
if ((r0|r1) < 8 && i0 >= 0 && !(i0 & 1) && (i0 >> 1) < 0x20)
|
|
T1_LDRHI(_jit, r0, r1, i0 >> 1);
|
|
else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
|
|
T2_LDRHI(_jit, r0, r1, i0);
|
|
else if (i0 < 0 && i0 >= -255)
|
|
T2_LDRHIN(_jit, r0, r1, -i0);
|
|
else if (i0 >= 0 && i0 <= 4095)
|
|
T2_LDRHWI(_jit, r0, r1, i0);
|
|
else if (r0 != r1) {
|
|
movi(_jit, r0, i0);
|
|
if ((r0|r1) < 8)
|
|
T1_LDRH(_jit, r0, r1, r0);
|
|
else
|
|
T2_LDRH(_jit, r0, r1, r0);
|
|
} else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
if ((r0|r1|jit_gpr_regno(reg)) < 8)
|
|
T1_LDRH(_jit, r0, r1, jit_gpr_regno(reg));
|
|
else
|
|
T2_LDRH(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
ldr_i(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
T2_LDRI(_jit, r0, r1, 0);
|
|
}
|
|
|
|
static void
|
|
ldi_i(jit_state_t *_jit, int32_t r0, jit_word_t i0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_LDRI(_jit, r0, jit_gpr_regno(reg), 0);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
ldxr_i(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8)
|
|
T1_LDR(_jit, r0, r1, r2);
|
|
else
|
|
T2_LDR(_jit, r0, r1, r2);
|
|
}
|
|
|
|
static void
|
|
ldxi_i(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
|
|
{
|
|
if ((r0|r1) < 8 && i0 >= 0 && !(i0 & 3) && (i0 >> 2) < 0x20)
|
|
T1_LDRI(_jit, r0, r1, i0 >> 2);
|
|
else if (r1 == jit_gpr_regno(JIT_SP) && r0 < 8 &&
|
|
i0 >= 0 && !(i0 & 3) && (i0 >> 2) <= 255)
|
|
T1_LDRISP(_jit, r0, i0 >> 2);
|
|
else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
|
|
T2_LDRI(_jit, r0, r1, i0);
|
|
else if (i0 < 0 && i0 > -255)
|
|
T2_LDRIN(_jit, r0, r1, -i0);
|
|
else if (i0 >= 0 && i0 <= 4095)
|
|
T2_LDRWI(_jit, r0, r1, i0);
|
|
else if (r0 != r1) {
|
|
movi(_jit, r0, i0);
|
|
if ((r0|r1) < 8)
|
|
T1_LDR(_jit, r0, r1, r0);
|
|
else
|
|
T2_LDR(_jit, r0, r1, r0);
|
|
} else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
if ((r0|r1|jit_gpr_regno(reg)) < 8)
|
|
T1_LDR(_jit, r0, r1, jit_gpr_regno(reg));
|
|
else
|
|
T2_LDR(_jit, r0, r1, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
str_c(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
T2_STRBI(_jit, r1, r0, 0);
|
|
}
|
|
|
|
static void
|
|
sti_c(jit_state_t *_jit, jit_word_t i0, int32_t r0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_STRBI(_jit, r0, jit_gpr_regno(reg), 0);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
stxr_c(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8)
|
|
T1_STRB(_jit, r2, r1, r0);
|
|
else
|
|
T2_STRB(_jit, r2, r1, r0);
|
|
}
|
|
|
|
static void
|
|
stxi_c(jit_state_t *_jit, jit_word_t i0, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8 && i0 >= 0 && i0 < 0x20)
|
|
T1_STRBI(_jit, r1, r0, i0);
|
|
else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
|
|
T2_STRBI(_jit, r1, r0, i0);
|
|
else if (i0 < 0 && i0 >= -255)
|
|
T2_STRBIN(_jit, r1, r0, -i0);
|
|
else if (i0 >= 0 && i0 <= 4095)
|
|
T2_STRBWI(_jit, r1, r0, i0);
|
|
else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
if ((r0|r1|jit_gpr_regno(reg)) < 8)
|
|
T1_STRB(_jit, r1, r0, jit_gpr_regno(reg));
|
|
else
|
|
T2_STRB(_jit, r1, r0, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
str_s(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
T2_STRHI(_jit, r1, r0, 0);
|
|
}
|
|
|
|
static void
|
|
sti_s(jit_state_t *_jit, jit_word_t i0, int32_t r0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_STRHI(_jit, r0, jit_gpr_regno(reg), 0);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
stxr_s(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8)
|
|
T1_STRH(_jit, r2, r1, r0);
|
|
else
|
|
T2_STRH(_jit, r2, r1, r0);
|
|
}
|
|
|
|
static void
|
|
stxi_s(jit_state_t *_jit, jit_word_t i0, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8 && i0 >= 0 && !(i0 & 1) && (i0 >> 1) < 0x20)
|
|
T1_STRHI(_jit, r1, r0, i0 >> 1);
|
|
else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
|
|
T2_STRHI(_jit, r1, r0, i0);
|
|
else if (i0 < 0 && i0 >= -255)
|
|
T2_STRHIN(_jit, r1, r0, -i0);
|
|
else if (i0 >= 0 && i0 <= 4095)
|
|
T2_STRHWI(_jit, r1, r0, i0);
|
|
else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
if ((r0|r1|jit_gpr_regno(reg)) < 8)
|
|
T1_STRH(_jit, r1, r0, jit_gpr_regno(reg));
|
|
else
|
|
T2_STRH(_jit, r1, r0, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
str_i(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
T2_STRI(_jit, r1, r0, 0);
|
|
}
|
|
|
|
static void
|
|
sti_i(jit_state_t *_jit, jit_word_t i0, int32_t r0)
|
|
{
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
T2_STRI(_jit, r0, jit_gpr_regno(reg), 0);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
stxr_i(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
|
|
{
|
|
if ((r0|r1|r2) < 8)
|
|
T1_STR(_jit, r2, r1, r0);
|
|
else
|
|
T2_STR(_jit, r2, r1, r0);
|
|
}
|
|
|
|
static void
|
|
stxi_i(jit_state_t *_jit, jit_word_t i0, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8 && i0 >= 0 && !(i0 & 3) && (i0 >> 2) < 0x20)
|
|
T1_STRI(_jit, r1, r0, i0 >> 2);
|
|
else if (r0 == jit_gpr_regno(JIT_SP) && r1 < 8 &&
|
|
i0 >= 0 && !(i0 & 3) && (i0 >> 2) <= 255)
|
|
T1_STRISP(_jit, r1, i0 >> 2);
|
|
else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
|
|
T2_STRI(_jit, r1, r0, i0);
|
|
else if (i0 < 0 && i0 >= -255)
|
|
T2_STRIN(_jit, r1, r0, -i0);
|
|
else if (i0 >= 0 && i0 <= 4095)
|
|
T2_STRWI(_jit, r1, r0, i0);
|
|
else {
|
|
jit_gpr_t reg = get_temp_gpr(_jit);
|
|
movi(_jit, jit_gpr_regno(reg), i0);
|
|
if ((r0|r1|jit_gpr_regno(reg)) < 8)
|
|
T1_STR(_jit, r1, r0, jit_gpr_regno(reg));
|
|
else
|
|
T2_STR(_jit, r1, r0, jit_gpr_regno(reg));
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
}
|
|
|
|
static void
|
|
bswapr_us(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8)
|
|
T1_REV(_jit, r0, r1);
|
|
else
|
|
T2_REV(_jit, r0, r1);
|
|
rshi_u(_jit, r0, r0, 16);
|
|
}
|
|
|
|
/* inline glibc htonl (without register clobber) */
|
|
static void
|
|
bswapr_ui(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8)
|
|
T1_REV(_jit, r0, r1);
|
|
else
|
|
T2_REV(_jit, r0, r1);
|
|
}
|
|
|
|
static void
|
|
extr_c(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
|
|
if ((r0|r1) < 8)
|
|
T1_SXTB(_jit, r0, r1);
|
|
else
|
|
T2_SXTB(_jit, r0, r1);
|
|
}
|
|
|
|
static void
|
|
extr_uc(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8)
|
|
T1_UXTB(_jit, r0, r1);
|
|
else
|
|
T2_UXTB(_jit, r0, r1);
|
|
}
|
|
|
|
static void
|
|
extr_s(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8)
|
|
T1_SXTH(_jit, r0, r1);
|
|
else
|
|
T2_SXTH(_jit, r0, r1);
|
|
}
|
|
|
|
static void
|
|
extr_us(jit_state_t *_jit, int32_t r0, int32_t r1)
|
|
{
|
|
if ((r0|r1) < 8)
|
|
T1_UXTH(_jit, r0, r1);
|
|
else
|
|
T2_UXTH(_jit, r0, r1);
|
|
}
|
|
|
|
static void
|
|
callr(jit_state_t *_jit, int32_t r0)
|
|
{
|
|
T1_BLX(_jit, r0);
|
|
}
|
|
|
|
static void
|
|
calli(jit_state_t *_jit, jit_word_t i0)
|
|
{
|
|
jit_patch_there(_jit, T2_BLI(_jit), (void*)i0);
|
|
}
|
|
|
|
static void
|
|
jmpi_with_link(jit_state_t *_jit, jit_word_t i0)
|
|
{
|
|
jit_patch_there(_jit, T2_BLI(_jit), (void*)i0);
|
|
}
|
|
|
|
static void
|
|
push_link_register(jit_state_t *_jit)
|
|
{
|
|
}
|
|
|
|
static void
|
|
pop_link_register(jit_state_t *_jit)
|
|
{
|
|
}
|
|
|
|
static void
|
|
ret(jit_state_t *_jit)
|
|
{
|
|
T1_BX(_jit, jit_gpr_regno(_LR));
|
|
}
|
|
|
|
static void
|
|
reti(jit_state_t *_jit, int32_t i0)
|
|
{
|
|
movi(_jit, jit_gpr_regno(_R0), i0);
|
|
ret(_jit);
|
|
}
|
|
|
|
static void
|
|
retr(jit_state_t *_jit, int32_t r0)
|
|
{
|
|
movr(_jit, jit_gpr_regno(_R0), r0);
|
|
ret(_jit);
|
|
}
|
|
|
|
static void
|
|
retval_c(jit_state_t *_jit, int32_t r0)
|
|
{
|
|
extr_c(_jit, r0, jit_gpr_regno(_R0));
|
|
}
|
|
|
|
static void
|
|
retval_uc(jit_state_t *_jit, int32_t r0)
|
|
{
|
|
extr_uc(_jit, r0, jit_gpr_regno(_R0));
|
|
}
|
|
|
|
static void
|
|
retval_s(jit_state_t *_jit, int32_t r0)
|
|
{
|
|
extr_s(_jit, r0, jit_gpr_regno(_R0));
|
|
}
|
|
|
|
static void
|
|
retval_us(jit_state_t *_jit, int32_t r0)
|
|
{
|
|
extr_us(_jit, r0, jit_gpr_regno(_R0));
|
|
}
|
|
|
|
static void
|
|
retval_i(jit_state_t *_jit, int32_t r0)
|
|
{
|
|
movr(_jit, r0, jit_gpr_regno(_R0));
|
|
}
|
|
|
|
static uint32_t*
|
|
jmp_without_veneer(jit_state_t *_jit)
|
|
{
|
|
uint32_t *loc = _jit->pc.ui;
|
|
emit_u16(_jit, 0);
|
|
emit_u16(_jit, 0);
|
|
return loc;
|
|
}
|
|
|
|
static void
|
|
patch_jmp_without_veneer(jit_state_t *_jit, uint32_t *loc)
|
|
{
|
|
uint8_t *pc_base = ((uint8_t *)loc) + 4;
|
|
int32_t off = (uint8_t*)jit_address(_jit) - pc_base;
|
|
write_wide_thumb(loc, THUMB2_B | encode_thumb_jump(off));
|
|
}
|
|
|
|
struct veneer
|
|
{
|
|
uint16_t ldr;
|
|
uint16_t br;
|
|
uint32_t addr;
|
|
};
|
|
|
|
static void
|
|
patch_veneer(uint32_t *loc, jit_pointer_t addr)
|
|
{
|
|
struct veneer *v = (struct veneer*) loc;
|
|
v->addr = (uintptr_t) addr;
|
|
}
|
|
|
|
static void
|
|
emit_veneer(jit_state_t *_jit, jit_pointer_t target)
|
|
{
|
|
uint16_t thumb1_ldr = 0x4800;
|
|
int32_t tmp = jit_gpr_regno(JIT_TMP1);
|
|
ASSERT(tmp < 8);
|
|
// Loaded addr is 4 bytes after the LDR, which is aligned, so offset is 0.
|
|
emit_u16(_jit, thumb1_ldr | (tmp << 8));
|
|
emit_u16(_jit, THUMB_BX|(_u4(tmp)<<3));
|
|
emit_u32(_jit, (uint32_t) target);
|
|
}
|
|
|
|
static void
|
|
ldr_atomic(jit_state_t *_jit, int32_t dst, int32_t loc)
|
|
{
|
|
T1_DMB(_jit, DMB_ISH);
|
|
ldr_i(_jit, dst, loc);
|
|
T1_DMB(_jit, DMB_ISH);
|
|
}
|
|
|
|
static void
|
|
str_atomic(jit_state_t *_jit, int32_t loc, int32_t val)
|
|
{
|
|
T1_DMB(_jit, DMB_ISH);
|
|
str_i(_jit, loc, val);
|
|
T1_DMB(_jit, DMB_ISH);
|
|
}
|
|
|
|
static void
|
|
swap_atomic(jit_state_t *_jit, int32_t dst, int32_t loc, int32_t val)
|
|
{
|
|
int32_t result = jit_gpr_regno(get_temp_gpr(_jit));
|
|
int32_t val_or_tmp = dst == val ? jit_gpr_regno(get_temp_gpr(_jit)) : val;
|
|
movr(_jit, val_or_tmp, val);
|
|
T1_DMB(_jit, DMB_ISH);
|
|
void *retry = jit_address(_jit);
|
|
T1_LDREX(_jit, dst, loc, 0);
|
|
T1_STREX(_jit, result, val_or_tmp, loc, 0);
|
|
jit_patch_there(_jit, bnei(_jit, result, 0), retry);
|
|
T1_DMB(_jit, DMB_ISH);
|
|
if (dst == val) unget_temp_gpr(_jit);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
cas_atomic(jit_state_t *_jit, int32_t dst, int32_t loc, int32_t expected,
|
|
int32_t desired)
|
|
{
|
|
int32_t dst_or_tmp;
|
|
if (dst == loc || dst == expected || dst == expected)
|
|
dst_or_tmp = jit_gpr_regno(get_temp_gpr(_jit));
|
|
else
|
|
dst_or_tmp = dst;
|
|
T1_DMB(_jit, DMB_ISH);
|
|
void *retry = jit_address(_jit);
|
|
T1_LDREX(_jit, dst_or_tmp, loc, 0);
|
|
jit_reloc_t bad = bner(_jit, dst_or_tmp, expected);
|
|
int result = jit_gpr_regno(get_temp_gpr(_jit));
|
|
T1_STREX(_jit, result, desired, loc, 0);
|
|
jit_patch_there(_jit, bnei(_jit, result, 0), retry);
|
|
unget_temp_gpr(_jit);
|
|
jit_patch_here(_jit, bad);
|
|
T1_DMB(_jit, DMB_ISH);
|
|
movr(_jit, dst, dst_or_tmp);
|
|
unget_temp_gpr(_jit);
|
|
}
|
|
|
|
static void
|
|
breakpoint(jit_state_t *_jit)
|
|
{
|
|
T1_BRK(_jit);
|
|
}
|