/******************************** -*- C -*- ****************************
 *
 *	Support macros for arm software floating-point math
 *
 ***********************************************************************/


/***********************************************************************
 *
 * Copyright 2011 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.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with GNU lightning; see the file COPYING.LESSER; if not, write to the
 * Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 ***********************************************************************/


#ifndef __lightning_fp_swf_h
#define __lightning_fp_swf_h

#if 0
#include <math.h>

#define swf_off(rn)				((rn) << 2)

extern float	__addsf3(float, float);
extern double	__adddf3(double, double);
extern float	__aeabi_fsub(float, float);
extern double	__aeabi_dsub(double, double);
extern float	__aeabi_fmul(float, float);
extern double	__aeabi_dmul(double, double);
extern float	__aeabi_fdiv(float, float);
extern double	__aeabi_ddiv(double, double);
extern float	__aeabi_i2f(int);
extern double	__aeabi_i2d(int);
extern float	__aeabi_d2f(double);
extern double	__aeabi_f2d(float);
extern int	__aeabi_f2iz(double);
extern int	__aeabi_d2iz(float);
extern int	__aeabi_fcmplt(float, float);
extern int	__aeabi_dcmplt(double, double);
extern int	__aeabi_fcmple(float, float);
extern int	__aeabi_dcmple(double, double);
extern int	__aeabi_fcmpeq(float, float);
extern int	__aeabi_dcmpeq(double, double);
extern int	__aeabi_fcmpge(float, float);
extern int	__aeabi_dcmpge(double, double);
extern int	__aeabi_fcmpgt(float, float);
extern int	__aeabi_dcmpgt(double, double);
extern int	__aeabi_fcmpun(float, float);
extern int	__aeabi_dcmpun(double, double);

#define swf_call(function, label)					\
    do {								\
	int	d;							\
	if (!jit_exchange_p()) {					\
	    if (jit_thumb_p())						\
		d = (((int)function - (int)_jit->x.pc) >> 1) - 2;	\
	    else							\
		d = (((int)function - (int)_jit->x.pc) >> 2) - 2;	\
	    if (_s24P(d)) {						\
		if (jit_thumb_p())					\
		    T2_BLI(encode_thumb_jump(d));			\
		else							\
		    _BLI(d & 0x00ffffff);				\
	    }								\
	    else							\
		goto label;						\
	}								\
	else {								\
	label:								\
	    jit_movi_i(JIT_FTMP, (int)function);			\
	    if (jit_thumb_p())						\
		T1_BLX(JIT_FTMP);					\
	    else							\
		_BLX(JIT_FTMP);						\
	}								\
    } while (0)
#define swf_ldrin(rt, rn, im)						\
    do {								\
	if (jit_thumb_p())	T2_LDRIN(rt, rn, im);			\
	else			_LDRIN(rt, rn, im);			\
    } while (0)
#define swf_strin(rt, rn, im)						\
    do {								\
	if (jit_thumb_p())	T2_STRIN(rt, rn, im);			\
	else			_STRIN(rt, rn, im);			\
    } while (0)
#define swf_push(mask)							\
    do {								\
	if (jit_thumb_p())	T1_PUSH(mask);				\
	else			_PUSH(mask);				\
    } while (0)
#define swf_pop(mask)							\
    do {								\
	if (jit_thumb_p())	T1_POP(mask);				\
	else			_POP(mask);				\
    } while (0)
#define swf_bici(rt, rn, im)						\
    do {								\
	if (jit_thumb_p())						\
	    T2_BICI(rt, rn, encode_thumb_immediate(im));		\
	else								\
	    _BICI(rt, rn, encode_arm_immediate(im));			\
    } while (0)

__jit_inline void
swf_movr_f(jit_state_t _jit, jit_fpr_t r0, jit_fpr_t r1)
{
    if (r0 != r1) {
	if (r0 == JIT_FPRET)
	    /* jit_ret() must follow! */
	    swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
	else {
	    swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r1) + 8);
	    swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
	}
    }
}

__jit_inline void
swf_movr_d(jit_state_t _jit, jit_fpr_t r0, jit_fpr_t r1)
{
    if (r0 != r1) {
	if (!jit_thumb_p() && jit_armv5e_p()) {
	    if (r0 == JIT_FPRET)
		/* jit_ret() must follow! */
		_LDRDIN(_R0, JIT_FP, swf_off(r1) + 8);
	    else {
		_LDRDIN(JIT_TMP, JIT_FP, swf_off(r1) + 8);
		_STRDIN(JIT_TMP, JIT_FP, swf_off(r0) + 8);
	    }
	}
	else {
	    if (r0 == JIT_FPRET) {
		/* jit_ret() must follow! */
		swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
		swf_ldrin(_R1, JIT_FP, swf_off(r1) + 4);
	    }
	    else {
		swf_ldrin(JIT_TMP, JIT_FP, swf_off(r1) + 8);
		swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r1) + 4);
		swf_strin(JIT_TMP, JIT_FP, swf_off(r0) + 8);
		swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 4);
	    }
	}
    }
}

__jit_inline void
swf_movi_f(jit_state_t _jit, jit_fpr_t r0, float i0)
{
    union {
	int	i;
	float	f;
    } u;
    u.f = i0;
    if (r0 == JIT_FPRET)
	/* jit_ret() must follow! */
	jit_movi_i(_R0, u.i);
    else {
	jit_movi_i(JIT_FTMP, u.i);
	swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
    }
}

__jit_inline void
swf_movi_d(jit_state_t _jit, jit_fpr_t r0, double i0)
{
    union {
	int	i[2];
	double	d;
    } u;
    u.d = i0;
    if (r0 == JIT_FPRET) {
	/* jit_ret() must follow! */
	jit_movi_i(_R0, u.i[0]);
	jit_movi_i(_R1, u.i[1]);
    }
    else {
	jit_movi_i(JIT_FTMP, u.i[0]);
	swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
	jit_movi_i(JIT_FTMP, u.i[1]);
	swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 4);
    }
}

__jit_inline void
swf_extr_i_f(jit_state_t _jit, jit_fpr_t r0, jit_gpr_t r1)
{
    swf_push(0xf);
    if (r1 != _R0)
	jit_movr_i(_R0, r1);
    swf_call(__aeabi_i2f, i2f);
    swf_strin(_R0, JIT_FP, swf_off(r0) + 8);
    swf_pop(0xf);
}

__jit_inline void
swf_extr_i_d(jit_state_t _jit, jit_fpr_t r0, jit_gpr_t r1)
{
    swf_push(0xf);
    if (r1 != _R0)
	jit_movr_i(_R0, r1);
    swf_call(__aeabi_i2d, i2d);
    if (!jit_thumb_p() && jit_armv5e_p())
	_STRDIN(_R0, JIT_FP, swf_off(r0) + 8);
    else {
	swf_strin(_R0, JIT_FP, swf_off(r0) + 8);
	swf_strin(_R1, JIT_FP, swf_off(r0) + 4);
    }
    swf_pop(0xf);
}

static void
swf_extr_d_f(jit_state_t _jit, jit_fpr_t r0, jit_fpr_t r1)
{
    swf_push(0xf);
    if (!jit_thumb_p() && jit_armv5e_p())
	_LDRDIN(_R0, JIT_FP, swf_off(r1) + 8);
    else {
	swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
	swf_ldrin(_R1, JIT_FP, swf_off(r1) + 4);
    }
    swf_call(__aeabi_d2f, d2f);
    swf_strin(_R0, JIT_FP, swf_off(r0) + 8);
    swf_pop(0xf);
}

static void
swf_extr_f_d(jit_state_t _jit, jit_fpr_t r0, jit_fpr_t r1)
{
    swf_push(0xf);
    swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
    swf_call(__aeabi_f2d, f2d);
    if (!jit_thumb_p() && jit_armv5e_p())
	_STRDIN(_R0, JIT_FP, swf_off(r0) + 8);
    else {
	swf_strin(_R0, JIT_FP, swf_off(r0) + 8);
	swf_strin(_R1, JIT_FP, swf_off(r0) + 4);
    }
    swf_pop(0xf);
}

static void
swf_if(jit_state_t _jit, float (*i0)(float), jit_gpr_t r0, jit_fpr_t r1)
{
    int			 l;
#if !NAN_TO_INT_IS_ZERO
    jit_insn		*is_nan;
    jit_insn		*fast_not_nan;
    jit_insn		*slow_not_nan;
#endif
    l = 0xf;
    if ((int)r0 < 4)
	/* bogus extra push to align at 8 bytes */
	l = (l & ~(1 << r0)) | 0x10;
    swf_push(l);
    swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
#if !NAN_TO_INT_IS_ZERO
    /* >> based on fragment of __aeabi_fcmpun */
    jit_lshi_i(JIT_FTMP, _R0, 1);
    if (jit_thumb_p())
	torrrs(THUMB2_MVN|ARM_S, _R0, JIT_TMP, JIT_FTMP,
	       encode_thumb_shift(24, ARM_ASR));
    else
	corrrs(ARM_CC_AL,ARM_MVN|ARM_S|ARM_ASR, _R0, JIT_TMP, JIT_FTMP, 24);
    fast_not_nan = _jit->x.pc;
    if (jit_thumb_p()) {
	T2_CC_B(ARM_CC_NE, 0);
	tshift(THUMB2_LSLI|ARM_S, _R0, JIT_TMP, 9);
    }
    else {
	_CC_B(ARM_CC_NE, 0);
	cshift(ARM_CC_AL, ARM_S|ARM_LSL, _R0, JIT_TMP, _R0, 9);
    }
    slow_not_nan = _jit->x.pc;
    if (jit_thumb_p())
	T2_CC_B(ARM_CC_EQ, 0);
    else
	_CC_B(ARM_CC_EQ, 0);
    jit_movi_i(r0, 0x80000000);
    is_nan = _jit->x.pc;
    if (jit_thumb_p())
	T2_B(0);
    else
	_B(ARM_CC_AL, 0);
    jit_patch(fast_not_nan);
    jit_patch(slow_not_nan);
    /* << based on fragment of __aeabi_fcmpun */
#endif
    if (i0)
	swf_call(i0, fallback);
    swf_call(__aeabi_f2iz, f2iz);
    jit_movr_i(r0, _R0);
#if !NAN_TO_INT_IS_ZERO
    jit_patch(is_nan);
#endif
    swf_pop(l);
}

static void
swf_id(jit_state_t _jit, double (*i0)(double), jit_gpr_t r0, jit_fpr_t r1)
{
    int			 l;
#if !NAN_TO_INT_IS_ZERO
    jit_insn		*is_nan;
    jit_insn		*fast_not_nan;
    jit_insn		*slow_not_nan;
#endif
    l = 0xf;
    if ((int)r0 < 4)
	/* bogus extra push to align at 8 bytes */
	l = (l & ~(1 << r0)) | 0x10;
    swf_push(l);
    if (!jit_thumb_p() && jit_armv5e_p())
	_LDRDIN(_R0, JIT_FP, swf_off(r1) + 8);
    else {
	swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
	swf_ldrin(_R1, JIT_FP, swf_off(r1) + 4);
    }
#if !NAN_TO_INT_IS_ZERO
    /* >> based on fragment of __aeabi_dcmpun */
    jit_lshi_i(JIT_TMP, _R1, 1);
    if (jit_thumb_p())
	torrrs(THUMB2_MVN|ARM_S, _R0, JIT_TMP, JIT_TMP,
	       encode_thumb_shift(21, ARM_ASR));
    else
	corrrs(ARM_CC_AL,ARM_MVN|ARM_S|ARM_ASR, _R0, JIT_TMP, JIT_TMP, 21);
    fast_not_nan = _jit->x.pc;
    if (jit_thumb_p()) {
	T2_CC_B(ARM_CC_NE, 0);
	torrrs(THUMB2_ORR|ARM_S, _R0, JIT_TMP, _R1,
	       encode_thumb_shift(12, ARM_LSL));
    }
    else {
	_CC_B(ARM_CC_NE, 0);
	corrrs(ARM_CC_AL,ARM_ORR|ARM_S|ARM_LSL, _R0, JIT_TMP, _R1, 12);
    }
    slow_not_nan = _jit->x.pc;
    if (jit_thumb_p())
	T2_CC_B(ARM_CC_EQ, 0);
    else
	_CC_B(ARM_CC_EQ, 0);
    jit_movi_i(r0, 0x80000000);
    is_nan = _jit->x.pc;
    if (jit_thumb_p())
	T2_B(0);
    else
	_B(0);
    jit_patch(fast_not_nan);
    jit_patch(slow_not_nan);
    /* << based on fragment of __aeabi_dcmpun */
#endif
    if (i0)
	swf_call(i0, fallback);
    swf_call(__aeabi_d2iz, d2iz);
    jit_movr_i(r0, _R0);
#if !NAN_TO_INT_IS_ZERO
    jit_patch(is_nan);
#endif
    swf_pop(l);
}

#define swf_rintr_f_i(_jit, r0, r1)	swf_if(_jit, rintf, r0, r1)
#define swf_rintr_d_i(_jit, r0, r1)	swf_id(_jit, rint, r0, r1)
#define swf_roundr_f_i(_jit, r0, r1)	swf_if(_jit, roundf, r0, r1)
#define swf_roundr_d_i(_jit, r0, r1)	swf_id(_jit, round, r0, r1)
#define swf_truncr_f_i(_jit, r0, r1)	swf_if(_jit, (void *)0, r0, r1)
#define swf_truncr_d_i(_jit, r0, r1)	swf_id(_jit, (void *)0, r0, r1)
#define swf_ceilr_f_i(_jit, r0, r1)	swf_if(_jit, ceilf, r0, r1)
#define swf_ceilr_d_i(_jit, r0, r1)	swf_id(_jit, ceil, r0, r1)
#define swf_floorr_f_i(_jit, r0, r1)	swf_if(_jit, floorf, r0, r1)
#define swf_floorr_d_i(_jit, r0, r1)	swf_id(_jit, floor, r0, r1)

__jit_inline void
swf_absr_f(jit_state_t _jit, jit_fpr_t r0, jit_fpr_t r1)
{
    swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r1) + 8);
    swf_bici(JIT_FTMP, JIT_FTMP, 0x80000000);
    swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
}

__jit_inline void
swf_absr_d(jit_state_t _jit, jit_fpr_t r0, jit_fpr_t r1)
{
    swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r1) + 4);
    swf_bici(JIT_FTMP, JIT_FTMP,  0x80000000);
    swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 4);
    if (r0 != r1) {
	swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r1) + 8);
	swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
    }
}

__jit_inline void
swf_negr_f(jit_state_t _jit, jit_fpr_t r0, jit_fpr_t r1)
{
    swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r1) + 8);
    jit_xori_i(JIT_FTMP, JIT_FTMP,  0x80000000);
    swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
}

__jit_inline void
swf_negr_d(jit_state_t _jit, jit_fpr_t r0, jit_fpr_t r1)
{
    swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r1) + 4);
    jit_xori_i(JIT_FTMP, JIT_FTMP,  0x80000000);
    swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 4);
    if (r0 != r1) {
	swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r1) + 8);
	swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
    }
}

static void
swf_ff(jit_state_t _jit, float (*i0)(float), jit_fpr_t r0, jit_fpr_t r1)
{
    swf_push(0xf);
    swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
    swf_call(i0, fallback);
    swf_strin(_R0, JIT_FP, swf_off(r0) + 8);
    swf_pop(0xf);
}

static void
swf_dd(jit_state_t _jit, double (*i0)(double), jit_fpr_t r0, jit_fpr_t r1)
{
    swf_push(0xf);
    if (!jit_thumb_p() && jit_armv5e_p())
	_LDRDIN(_R0, JIT_FP, swf_off(r1) + 8);
    else {
	swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
	swf_ldrin(_R1, JIT_FP, swf_off(r1) + 4);
    }
    swf_call(i0, fallback);
    if (!jit_thumb_p() && jit_armv5e_p())
	_STRDIN(_R0, JIT_FP, swf_off(r0) + 8);
    else {
	swf_strin(_R0, JIT_FP, swf_off(r0) + 8);
	swf_strin(_R1, JIT_FP, swf_off(r0) + 4);
    }
    swf_pop(0xf);
}

#define swf_sqrtr_f(_jit, r0, r1)	swf_ff(_jit, sqrtf, r0, r1)
#define swf_sqrtr_d(_jit, r0, r1)	swf_dd(_jit, sqrt, r0, r1)

static void
swf_fff(jit_state_t _jit, float (*i0)(float, float),
	 jit_fpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    swf_push(0xf);
    swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
    swf_ldrin(_R1, JIT_FP, swf_off(r2) + 8);
    swf_call(i0, fallback);
    swf_strin(_R0, JIT_FP, swf_off(r0) + 8);
    swf_pop(0xf);
}

static void
swf_ddd(jit_state_t _jit, double (*i0)(double, double),
	 jit_fpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    swf_push(0xf);
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRDIN(_R0, JIT_FP, swf_off(r1) + 8);
	_LDRDIN(_R2, JIT_FP, swf_off(r2) + 8);
    }
    else {
	swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
	swf_ldrin(_R1, JIT_FP, swf_off(r1) + 4);
	swf_ldrin(_R2, JIT_FP, swf_off(r2) + 8);
	swf_ldrin(_R3, JIT_FP, swf_off(r2) + 4);
    }
    swf_call(i0, fallback);
    if (!jit_thumb_p() && jit_armv5e_p())
	_STRDIN(_R0, JIT_FP, swf_off(r0) + 8);
    else {
	swf_strin(_R0, JIT_FP, swf_off(r0) + 8);
	swf_strin(_R1, JIT_FP, swf_off(r0) + 4);
    }
    swf_pop(0xf);
}

#define swf_addr_f(_jit, r0, r1, r2)	swf_fff(_jit, __addsf3, r0, r1, r2)
#define swf_addr_d(_jit, r0, r1, r2)	swf_ddd(_jit, __adddf3, r0, r1, r2)
#define swf_subr_f(_jit, r0, r1, r2)	swf_fff(_jit, __aeabi_fsub, r0, r1, r2)
#define swf_subr_d(_jit, r0, r1, r2)	swf_ddd(_jit, __aeabi_dsub, r0, r1, r2)
#define swf_mulr_f(_jit, r0, r1, r2)	swf_fff(_jit, __aeabi_fmul, r0, r1, r2)
#define swf_mulr_d(_jit, r0, r1, r2)	swf_ddd(_jit, __aeabi_dmul, r0, r1, r2)
#define swf_divr_f(_jit, r0, r1, r2)	swf_fff(_jit, __aeabi_fdiv, r0, r1, r2)
#define swf_divr_d(_jit, r0, r1, r2)	swf_ddd(_jit, __aeabi_ddiv, r0, r1, r2)

static void
swf_iff(jit_state_t _jit, int (*i0)(float, float),
	jit_gpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    int			l;
    l = 0xf;
    if ((int)r0 < 4)
	/* bogus extra push to align at 8 bytes */
	l = (l & ~(1 << r0)) | 0x10;
    swf_push(l);
    swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
    swf_ldrin(_R1, JIT_FP, swf_off(r2) + 8);
    swf_call(i0, fallback);
    jit_movr_i(r0, _R0);
    swf_pop(l);
}

static void
swf_idd(jit_state_t _jit, int (*i0)(double, double),
	jit_fpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    int			l;
    l = 0xf;
    if ((int)r0 < 4)
	/* bogus extra push to align at 8 bytes */
	l = (l & ~(1 << r0)) | 0x10;
    swf_push(l);
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRDIN(_R0, JIT_FP, swf_off(r1) + 8);
	_LDRDIN(_R2, JIT_FP, swf_off(r2) + 8);
    }
    else {
	swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
	swf_ldrin(_R1, JIT_FP, swf_off(r1) + 4);
	swf_ldrin(_R2, JIT_FP, swf_off(r2) + 8);
	swf_ldrin(_R3, JIT_FP, swf_off(r2) + 4);
    }
    swf_call(i0, fallback);
    jit_movr_i(r0, _R0);
    swf_pop(l);
}

#define swf_ltr_f(_jit, r0, r1, r2)	swf_iff(_jit, __aeabi_fcmplt,r0,r1,r2)
#define swf_ltr_d(_jit, r0, r1, r2)	swf_idd(_jit, __aeabi_dcmplt,r0,r1,r2)
#define swf_ler_f(_jit, r0, r1, r2)	swf_iff(_jit, __aeabi_fcmple,r0,r1,r2)
#define swf_ler_d(_jit, r0, r1, r2)	swf_idd(_jit, __aeabi_dcmple,r0,r1,r2)
#define swf_eqr_f(_jit, r0, r1, r2)	swf_iff(_jit, __aeabi_fcmpeq,r0,r1,r2)
#define swf_eqr_d(_jit, r0, r1, r2)	swf_idd(_jit, __aeabi_dcmpeq,r0,r1,r2)
#define swf_ger_f(_jit, r0, r1, r2)	swf_iff(_jit, __aeabi_fcmpge,r0,r1,r2)
#define swf_ger_d(_jit, r0, r1, r2)	swf_idd(_jit, __aeabi_dcmpge,r0,r1,r2)
#define swf_gtr_f(_jit, r0, r1, r2)	swf_iff(_jit, __aeabi_fcmpgt,r0,r1,r2)
#define swf_gtr_d(_jit, r0, r1, r2)	swf_idd(_jit, __aeabi_dcmpgt,r0,r1,r2)

__jit_inline void
swf_ner_f(jit_state_t _jit, jit_gpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    swf_iff(_jit, __aeabi_fcmpeq, r0, r1, r2);
    jit_xori_i(r0, r0, 1);
}

__jit_inline void
swf_ner_d(jit_state_t _jit, jit_gpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    swf_idd(_jit, __aeabi_dcmpeq, r0, r1, r2);
    jit_xori_i(r0, r0, 1);
}

static void
swf_iunff(jit_state_t _jit, int (*i0)(float, float),
	  jit_gpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    int			 l;
    jit_insn		*i;
    l = 0xf;
    if ((int)r0 < 4)
	/* bogus extra push to align at 8 bytes */
	l = (l & ~(1 << r0)) | 0x10;
    swf_push(l);
    swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
    swf_ldrin(_R1, JIT_FP, swf_off(r2) + 8);
    swf_call(__aeabi_fcmpun, fcmpun);
    if (jit_thumb_p()) {
	T1_CMPI(_R0, 0);
	_IT(ARM_CC_NE);
	if (r0 < 8)
	    T1_MOVI(r0, 1);
	else
	    T2_MOVI(r0, 1);
	i = _jit->x.pc;
	T2_CC_B(ARM_CC_NE, 0);
    }
    else {
	_CMPI(_R0, 0);
	_CC_MOVI(ARM_CC_NE, r0, 1);
	i = _jit->x.pc;
	_CC_B(ARM_CC_NE, 0);
    }
    swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
    swf_ldrin(_R1, JIT_FP, swf_off(r2) + 8);
    swf_call(i0, fallback);
    jit_movr_i(r0, _R0);
    jit_patch(i);
    swf_pop(l);
}

static void
swf_iundd(jit_state_t _jit, int (*i0)(double, double),
	  jit_gpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    int			 l;
    jit_insn		*i;
    l = 0xf;
    if ((int)r0 < 4)
	/* bogus extra push to align at 8 bytes */
	l = (l & ~(1 << r0)) | 0x10;
    swf_push(l);
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRDIN(_R0, JIT_FP, swf_off(r1) + 8);
	_LDRDIN(_R2, JIT_FP, swf_off(r2) + 8);
    }
    else {
	swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
	swf_ldrin(_R1, JIT_FP, swf_off(r1) + 4);
	swf_ldrin(_R2, JIT_FP, swf_off(r2) + 8);
	swf_ldrin(_R3, JIT_FP, swf_off(r2) + 4);
    }
    swf_call(__aeabi_dcmpun, dcmpun);
    if (jit_thumb_p()) {
	T1_CMPI(_R0, 0);
	_IT(ARM_CC_NE);
	if (r0 < 8)
	    T1_MOVI(r0, 1);
	else
	    T2_MOVI(r0, 1);
	i = _jit->x.pc;
	T2_CC_B(ARM_CC_NE, 0);
    }
    else {
	_CMPI(_R0, 0);
	_CC_MOVI(ARM_CC_NE, r0, 1);
	i = _jit->x.pc;
	_CC_B(ARM_CC_NE, 0);
    }
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRDIN(_R0, JIT_FP, swf_off(r1) + 8);
	_LDRDIN(_R2, JIT_FP, swf_off(r2) + 8);
    }
    else {
	swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
	swf_ldrin(_R1, JIT_FP, swf_off(r1) + 4);
	swf_ldrin(_R2, JIT_FP, swf_off(r2) + 8);
	swf_ldrin(_R3, JIT_FP, swf_off(r2) + 4);
    }
    swf_call(i0, fallback);
    jit_movr_i(r0, _R0);
    jit_patch(i);
    swf_pop(l);
}

#define swf_unltr_f(_jit, r0, r1, r2)	swf_iunff(_jit,__aeabi_fcmplt,r0,r1,r2)
#define swf_unltr_d(_jit, r0, r1, r2)	swf_iundd(_jit,__aeabi_dcmplt,r0,r1,r2)
#define swf_unler_f(_jit, r0, r1, r2)	swf_iunff(_jit,__aeabi_fcmple,r0,r1,r2)
#define swf_unler_d(_jit, r0, r1, r2)	swf_iundd(_jit,__aeabi_dcmple,r0,r1,r2)
#define swf_uneqr_f(_jit, r0, r1, r2)	swf_iunff(_jit,__aeabi_fcmpeq,r0,r1,r2)
#define swf_uneqr_d(_jit, r0, r1, r2)	swf_iundd(_jit,__aeabi_dcmpeq,r0,r1,r2)
#define swf_unger_f(_jit, r0, r1, r2)	swf_iunff(_jit,__aeabi_fcmpge,r0,r1,r2)
#define swf_unger_d(_jit, r0, r1, r2)	swf_iundd(_jit,__aeabi_dcmpge,r0,r1,r2)
#define swf_ungtr_f(_jit, r0, r1, r2)	swf_iunff(_jit,__aeabi_fcmpgt,r0,r1,r2)
#define swf_ungtr_d(_jit, r0, r1, r2)	swf_iundd(_jit,__aeabi_dcmpgt,r0,r1,r2)

__jit_inline void
swf_ltgtr_f(jit_state_t _jit, jit_gpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    swf_iunff(_jit, __aeabi_fcmpeq, r0, r1, r2);
    jit_xori_i(r0, r0, 1);
}

__jit_inline void
swf_ltgtr_d(jit_state_t _jit, jit_gpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    swf_iundd(_jit, __aeabi_dcmpeq, r0, r1, r2);
    jit_xori_i(r0, r0, 1);
}

__jit_inline void
swf_ordr_f(jit_state_t _jit, jit_gpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    swf_iff(_jit, __aeabi_fcmpun, r0, r1, r2);
    jit_xori_i(r0, r0, 1);
}

__jit_inline void
swf_ordr_d(jit_state_t _jit, jit_gpr_t r0, jit_fpr_t r1, jit_fpr_t r2)
{
    swf_idd(_jit, __aeabi_dcmpun, r0, r1, r2);
    jit_xori_i(r0, r0, 1);
}

#define swf_unordr_f(_jit, r0, r1, r2)	swf_iunff(_jit,__aeabi_fcmpun,r0,r1,r2)
#define swf_unordr_d(_jit, r0, r1, r2)	swf_iundd(_jit,__aeabi_dcmpun,r0,r1,r2)

static jit_insn *
swf_bff(jit_state_t _jit, int (*i0)(float, float), int cc,
	void *i1, jit_fpr_t r1, jit_fpr_t r2)
{
    jit_insn		*l;
    int			 d;
    assert(r1 != JIT_FPRET && r2 != JIT_FPRET);
    swf_push(0xf);
    swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
    swf_ldrin(_R1, JIT_FP, swf_off(r2) + 8);
    swf_call(i0, fallback);
    if (jit_thumb_p()) {
	T1_CMPI(_R0, 0);
	swf_pop(0xf);
	l = _jit->x.pc;
	d = (((int)i1 - (int)l) >> 1) - 2;
	assert(_s20P(d));
	T2_CC_B(cc, encode_thumb_cc_jump(d));
    }
    else {
	_CMPI(_R0, 0);
	swf_pop(0xf);
	l = _jit->x.pc;
	d = (((int)i1 - (int)l) >> 2) - 2;
	assert(_s24P(d));
	_CC_B(cc, d & 0x00ffffff);
    }
    return (l);
}

static jit_insn *
swf_bdd(jit_state_t _jit, int (*i0)(double, double), int cc,
	void *i1, jit_fpr_t r1, jit_fpr_t r2)
{
    jit_insn		*l;
    int			 d;
    assert(r1 != JIT_FPRET && r2 != JIT_FPRET);
    swf_push(0xf);
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRDIN(_R0, JIT_FP, swf_off(r1) + 8);
	_LDRDIN(_R2, JIT_FP, swf_off(r2) + 8);
    }
    else {
	swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
	swf_ldrin(_R1, JIT_FP, swf_off(r1) + 4);
	swf_ldrin(_R2, JIT_FP, swf_off(r2) + 8);
	swf_ldrin(_R3, JIT_FP, swf_off(r2) + 4);
    }
    swf_call(i0, fallback);
    if (jit_thumb_p()) {
	T1_CMPI(_R0, 0);
	swf_pop(0xf);
	l = _jit->x.pc;
	d = (((int)i1 - (int)l) >> 1) - 2;
	assert(_s20P(d));
	T2_CC_B(cc, encode_thumb_cc_jump(d));
    }
    else {
	_CMPI(_R0, 0);
	swf_pop(0xf);
	l = _jit->x.pc;
	d = (((int)i1 - (int)l) >> 2) - 2;
	assert(_s24P(d));
	_CC_B(cc, d & 0x00ffffff);
    }
    return (l);
}

#define swf_bltr_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmplt,ARM_CC_NE,i0,r0,r1)
#define swf_bltr_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmplt,ARM_CC_NE,i0,r0,r1)
#define swf_bler_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmple,ARM_CC_NE,i0,r0,r1)
#define swf_bler_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmple,ARM_CC_NE,i0,r0,r1)
#define swf_beqr_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmpeq,ARM_CC_NE,i0,r0,r1)
#define swf_beqr_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmpeq,ARM_CC_NE,i0,r0,r1)
#define swf_bger_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmpge,ARM_CC_NE,i0,r0,r1)
#define swf_bger_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmpge,ARM_CC_NE,i0,r0,r1)
#define swf_bgtr_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmpgt,ARM_CC_NE,i0,r0,r1)
#define swf_bgtr_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmpgt,ARM_CC_NE,i0,r0,r1)
#define swf_bner_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmpeq,ARM_CC_EQ,i0,r0,r1)
#define swf_bner_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmpeq,ARM_CC_EQ,i0,r0,r1)
#define swf_bunltr_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmpge,ARM_CC_EQ,i0,r0,r1)
#define swf_bunltr_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmpge,ARM_CC_EQ,i0,r0,r1)
#define swf_bunler_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmpgt,ARM_CC_EQ,i0,r0,r1)
#define swf_bunler_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmpgt,ARM_CC_EQ,i0,r0,r1)

static jit_insn *
swf_bunff(jit_state_t _jit, int eq, void *i1, jit_fpr_t r1, jit_fpr_t r2)
{
    int			 d;
    jit_insn		*l;
    jit_insn		*j0;
    jit_insn		*j1;
    assert(r1 != JIT_FPRET && r2 != JIT_FPRET);
    swf_push(0xf);
    swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
    swf_ldrin(_R1, JIT_FP, swf_off(r2) + 8);
    swf_call(__aeabi_fcmpun, fcmpun);
    /* if unordered */
    if (jit_thumb_p()) {
	T1_CMPI(_R0, 0);
	j0 = _jit->x.pc;
	T2_CC_B(ARM_CC_NE, 0);
    }
    else {
	_CMPI(_R0, 0);
	j0 = _jit->x.pc;
	_CC_B(ARM_CC_NE, 0);
    }
    swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
    swf_ldrin(_R1, JIT_FP, swf_off(r2) + 8);
    swf_call(__aeabi_fcmpeq, fcmpeq);
    if (jit_thumb_p()) {
	T1_CMPI(_R0, 0);
	j1 = _jit->x.pc;
	if (eq) {
	    T2_CC_B(ARM_CC_EQ, 0);
	    jit_patch(j0);
	}
	else
	    T2_CC_B(ARM_CC_NE, 0);
	swf_pop(0xf);
	l = _jit->x.pc;
	d = (((int)i1 - (int)l) >> 1) - 2;
	assert(_s24P(d));
	T2_B(encode_thumb_jump(d));
    }
    else {
	_CMPI(_R0, 0);
	j1 = _jit->x.pc;
	if (eq) {
	    _CC_B(ARM_CC_EQ, 0);
	    jit_patch(j0);
	}
	else
	    _CC_B(ARM_CC_NE, 0);
	swf_pop(0xf);
	l = _jit->x.pc;
	d = (((int)i1 - (int)l) >> 2) - 2;
	assert(_s24P(d));
	_B(d & 0x00ffffff);
    }
    if (!eq)
	jit_patch(j0);
    jit_patch(j1);
    swf_pop(0xf);
    return (l);
}

static jit_insn *
swf_bundd(jit_state_t _jit, int eq, void *i1, jit_fpr_t r1, jit_fpr_t r2)
{
    int			 d;
    jit_insn		*l;
    jit_insn		*j0;
    jit_insn		*j1;
    assert(r1 != JIT_FPRET && r2 != JIT_FPRET);
    swf_push(0xf);
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRDIN(_R0, JIT_FP, swf_off(r1) + 8);
	_LDRDIN(_R2, JIT_FP, swf_off(r2) + 8);
    }
    else {
	swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
	swf_ldrin(_R1, JIT_FP, swf_off(r1) + 4);
	swf_ldrin(_R2, JIT_FP, swf_off(r2) + 8);
	swf_ldrin(_R3, JIT_FP, swf_off(r2) + 4);
    }
    swf_call(__aeabi_dcmpun, dcmpun);
    /* if unordered */
    if (jit_thumb_p()) {
	T1_CMPI(_R0, 0);
	j0 = _jit->x.pc;
	T2_CC_B(ARM_CC_NE, 0);
    }
    else {
	_CMPI(_R0, 0);
	j0 = _jit->x.pc;
	_CC_B(ARM_CC_NE, 0);
    }
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRDIN(_R0, JIT_FP, swf_off(r1) + 8);
	_LDRDIN(_R2, JIT_FP, swf_off(r2) + 8);
    }
    else {
	swf_ldrin(_R0, JIT_FP, swf_off(r1) + 8);
	swf_ldrin(_R1, JIT_FP, swf_off(r1) + 4);
	swf_ldrin(_R2, JIT_FP, swf_off(r2) + 8);
	swf_ldrin(_R3, JIT_FP, swf_off(r2) + 4);
    }
    swf_call(__aeabi_dcmpeq, dcmpeq);
    if (jit_thumb_p()) {
	T1_CMPI(_R0, 0);
	j1 = _jit->x.pc;
	if (eq) {
	    T2_CC_B(ARM_CC_EQ, 0);
	    jit_patch(j0);
	}
	else
	    T2_CC_B(ARM_CC_NE, 0);
	swf_pop(0xf);
	l = _jit->x.pc;
	d = (((int)i1 - (int)l) >> 1) - 2;
	assert(_s24P(d));
	T2_B(encode_thumb_jump(d));
    }
    else {
	_CMPI(_R0, 0);
	j1 = _jit->x.pc;
	if (eq) {
	    _CC_B(ARM_CC_EQ, 0);
	    jit_patch(j0);
	}
	else
	    _CC_B(ARM_CC_NE, 0);
	swf_pop(0xf);
	l = _jit->x.pc;
	d = (((int)i1 - (int)l) >> 2) - 2;
	assert(_s24P(d));
	_B(d & 0x00ffffff);
    }
    if (!eq)
	jit_patch(j0);
    jit_patch(j1);
    swf_pop(0xf);
    return (l);
}

#define swf_buneqr_f(_jit,i0,r0,r1)	swf_bunff(_jit,1,i0,r0,r1)
#define swf_buneqr_d(_jit,i0,r0,r1)	swf_bundd(_jit,1,i0,r0,r1)
#define swf_bunger_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmplt,ARM_CC_EQ,i0,r0,r1)
#define swf_bunger_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmplt,ARM_CC_EQ,i0,r0,r1)
#define swf_bungtr_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmple,ARM_CC_EQ,i0,r0,r1)
#define swf_bungtr_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmple,ARM_CC_EQ,i0,r0,r1)
#define swf_bltgtr_f(_jit,i0,r0,r1)	swf_bunff(_jit,0,i0,r0,r1)
#define swf_bltgtr_d(_jit,i0,r0,r1)	swf_bundd(_jit,0,i0,r0,r1)
#define swf_bordr_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmpun,ARM_CC_EQ,i0,r0,r1)
#define swf_bordr_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmpun,ARM_CC_EQ,i0,r0,r1)
#define swf_bunordr_f(_jit,i0,r0,r1)	swf_bff(_jit,__aeabi_fcmpun,ARM_CC_NE,i0,r0,r1)
#define swf_bunordr_d(_jit,i0,r0,r1)	swf_bdd(_jit,__aeabi_dcmpun,ARM_CC_NE,i0,r0,r1)

__jit_inline void
swf_ldr_f(jit_state_t _jit, jit_fpr_t r0, jit_gpr_t r1)
{
    jit_ldr_i(JIT_FTMP, r1);
    swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
}

__jit_inline void
swf_ldr_d(jit_state_t _jit, jit_fpr_t r0, jit_gpr_t r1)
{
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRDI(JIT_TMP, r1, 0);
	_STRDIN(JIT_TMP, JIT_FP, swf_off(r0) + 8);
    }
    else {
	jit_ldxi_i(JIT_TMP, r1, 0);
	jit_ldxi_i(JIT_FTMP, r1, 4);
	swf_strin(JIT_TMP, JIT_FP, swf_off(r0) + 8);
	swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 4);
    }
}

__jit_inline void
swf_ldi_f(jit_state_t _jit, jit_fpr_t r0, void *i0)
{
    jit_ldi_i(JIT_FTMP, i0);
    swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
}

__jit_inline void
swf_ldi_d(jit_state_t _jit, jit_fpr_t r0, void *i0)
{
    jit_movi_i(JIT_TMP, (int)i0);
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRDI(JIT_TMP, JIT_TMP, 0);
	_STRDIN(JIT_TMP, JIT_FP, swf_off(r0) + 8);
    }
    else {
	jit_ldxi_i(JIT_FTMP, JIT_TMP, 4);
	jit_ldxi_i(JIT_TMP, JIT_TMP, 0);
	swf_strin(JIT_TMP, JIT_FP, swf_off(r0) + 8);
	swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 4);
    }
}

__jit_inline void
swf_ldxr_f(jit_state_t _jit, jit_fpr_t r0, jit_gpr_t r1, jit_gpr_t r2)
{
    jit_ldxr_i(JIT_TMP, r1, r2);
    swf_strin(JIT_TMP, JIT_FP, swf_off(r0) + 8);
}

__jit_inline void
swf_ldxr_d(jit_state_t _jit, jit_fpr_t r0, jit_gpr_t r1, jit_gpr_t r2)
{
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRD(JIT_TMP, r1, r2);
	_STRDIN(JIT_TMP, JIT_FP, swf_off(r0) + 8);
    }
    else {
	jit_addr_i(JIT_TMP, r1, r2);
	jit_ldxi_i(JIT_FTMP, JIT_TMP, 4);
	jit_ldxi_i(JIT_TMP, JIT_TMP, 0);
	swf_strin(JIT_TMP, JIT_FP, swf_off(r0) + 8);
	swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 4);
    }
}

__jit_inline void
swf_ldxi_f(jit_state_t _jit, jit_fpr_t r0, jit_gpr_t r1, int i0)
{
    jit_ldxi_i(JIT_FTMP, r1, i0);
    swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
}

__jit_inline void
swf_ldxi_d(jit_state_t _jit, jit_fpr_t r0, jit_gpr_t r1, int i0)
{
    if (!jit_thumb_p() && jit_armv5e_p()) {
	if (i0 >= 0 && i0 <= 255)
	    _LDRDI(JIT_TMP, r1, i0);
	else if (i0 < 0 && i0 >= -255)
	    _LDRDIN(JIT_TMP, r1, -i0);
	else {
	    jit_addi_i(JIT_FTMP, r1, i0);
	    _LDRDI(JIT_TMP, JIT_FTMP, 0);
	}
	_STRDIN(JIT_TMP, JIT_FP, swf_off(r0) + 8);
    }
    else {
	if (((jit_thumb_p() && i0 >= -255) ||
	     (!jit_thumb_p() && i0 >= -4095)) && i0 + 4 <= 4095) {
	    if (i0 >= 0)
		jit_ldxi_i(JIT_TMP, r1, i0);
	    else if (i0 < 0)
		swf_ldrin(JIT_TMP, r1, -i0);
	    i0 += 4;
	    if (i0 >= 0)
		jit_ldxi_i(JIT_FTMP, r1, i0);
	    else if (i0 < 0)
		swf_ldrin(JIT_FTMP, r1, -i0);
	}
	else {
	    jit_addi_i(JIT_FTMP, r1, i0);
	    jit_ldxi_i(JIT_TMP, JIT_FTMP, 0);
	    jit_ldxi_i(JIT_FTMP, JIT_FTMP, 4);
	}
	swf_strin(JIT_TMP, JIT_FP, swf_off(r0) + 8);
	swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 4);
    }
}

__jit_inline void
swf_str_f(jit_state_t _jit, jit_gpr_t r0, jit_fpr_t r1)
{
    swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r1) + 8);
    jit_stxi_i(0, r0, JIT_FTMP);
}

__jit_inline void
swf_str_d(jit_state_t _jit, jit_gpr_t r0, jit_fpr_t r1)
{
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRDIN(JIT_TMP, JIT_FP, swf_off(r1) + 8);
	_STRDI(JIT_TMP, r0, 0);
    }
    else {
	swf_ldrin(JIT_TMP, JIT_FP, swf_off(r1) + 8);
	swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r1) + 4);
	jit_stxi_i(0, r0, JIT_TMP);
	jit_stxi_i(4, r0, JIT_FTMP);
    }
}

__jit_inline void
swf_sti_f(jit_state_t _jit, void *i0, jit_fpr_t r0)
{
    jit_movi_i(JIT_TMP, (int)i0);
    swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
    jit_stxi_i(0, JIT_TMP, JIT_FTMP);
}

__jit_inline void
swf_sti_d(jit_state_t _jit, void *i0, jit_fpr_t r0)
{
    jit_movi_i(JIT_TMP, (int)i0);
    swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
   jit_stxi_i(0, JIT_TMP, JIT_FTMP);
    swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r0) + 4);
   jit_stxi_i(4, JIT_TMP, JIT_FTMP);
}

__jit_inline void
swf_stxr_f(jit_state_t _jit, jit_gpr_t r0, jit_gpr_t r1, jit_fpr_t r2)
{
    swf_ldrin(JIT_TMP, JIT_FP, swf_off(r2) + 8);
    jit_stxr_i(r1, r0, JIT_TMP);
}

__jit_inline void
swf_stxr_d(jit_state_t _jit, jit_gpr_t r0, jit_gpr_t r1, jit_fpr_t r2)
{
    if (!jit_thumb_p() && jit_armv5e_p()) {
	_LDRDIN(JIT_TMP, JIT_FP, swf_off(r2) + 8);
	_STRD(JIT_TMP, r0, r1);
    }
    else {
	jit_addr_i(JIT_TMP, r0, r1);
	swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r2) + 8);
	jit_stxi_i(0, JIT_TMP, JIT_FTMP);
	swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r2) + 4);
	jit_stxi_i(4, JIT_TMP, JIT_FTMP);
    }
}

__jit_inline void
swf_stxi_f(jit_state_t _jit, int i0, jit_gpr_t r0, jit_fpr_t r1)
{
    swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r1) + 8);
    jit_stxi_i(i0, r0, JIT_FTMP);
}

__jit_inline void
swf_stxi_d(jit_state_t _jit, int i0, jit_gpr_t r0, jit_fpr_t r1)
{
    if (!jit_thumb_p() && jit_armv5e_p()) {
	if (i0 >= 0 && i0 <= 255) {
	    _LDRDIN(JIT_TMP, JIT_FP, swf_off(r1) + 8);
	    _STRDI(JIT_TMP, r0, i0);
	}
	else if (i0 < 0 && i0 >= -255) {
	    _LDRDIN(JIT_TMP, JIT_FP, swf_off(r1) + 8);
	    _STRDIN(JIT_TMP, r0, -i0);
	}
	else {
	    jit_addi_i(JIT_FTMP, r0, i0);
	    swf_ldrin(JIT_TMP, JIT_FP, swf_off(r1) + 8);
	    jit_stxi_i(0, JIT_TMP, JIT_FTMP);
	    swf_ldrin(JIT_TMP, JIT_FP, swf_off(r1) + 4);
	    jit_stxi_i(4, JIT_TMP, JIT_FTMP);
	}
    }
    else {
	jit_addi_i(JIT_FTMP, r0, i0);
	swf_ldrin(JIT_TMP, JIT_FP, swf_off(r1) + 8);
	jit_stxi_i(0, JIT_FTMP, JIT_TMP);
	swf_ldrin(JIT_TMP, JIT_FP, swf_off(r1) + 4);
	jit_stxi_i(4, JIT_FTMP, JIT_TMP);
    }
}

__jit_inline void
swf_getarg_f(jit_state_t _jit, jit_fpr_t r0, int i0)
{
    if (i0 < 4)
	i0 <<= 2;
    jit_ldxi_i(JIT_FTMP, JIT_FP, i0);
    swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
}

__jit_inline void
swf_getarg_d(jit_state_t _jit, jit_fpr_t r0, int i0)
{
    if (i0 < 4)
	i0 <<= 2;
    if (!jit_thumb_p() && jit_armv5e_p()) {
	if (i0 < 255)
	    _LDRDI(JIT_TMP, JIT_FP, i0);
	else {
	    jit_addi_i(JIT_FTMP, JIT_FP, i0);
	    jit_ldxi_i(JIT_TMP, JIT_FTMP, 0);
	    jit_ldxi_i(JIT_FTMP, JIT_FTMP, 4);
	}
	_STRDIN(JIT_TMP, JIT_FP, swf_off(r0) + 8);
    }
    else {
	if (i0 + 4 < 4095) {
	    jit_ldxi_i(JIT_TMP, JIT_FP, i0);
	    jit_ldxi_i(JIT_FTMP, JIT_FP, i0 + 4);
	}
	else {
	    jit_addi_i(JIT_FTMP, JIT_FP, i0);
	    jit_ldxi_i(JIT_TMP, JIT_FTMP, 0);
	    jit_ldxi_i(JIT_FTMP, JIT_FTMP, 4);
	}
	swf_strin(JIT_TMP, JIT_FP, swf_off(r0) + 8);
	swf_strin(JIT_FTMP, JIT_FP, swf_off(r0) + 4);
    }
}

__jit_inline void
swf_pusharg_f(jit_state_t _jit, jit_fpr_t r0)
{
    int		ofs = _jitl.nextarg_put++;
    assert(ofs < 256);
    _jitl.stack_offset -= sizeof(float);
    swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r0) + 8);
    _jitl.arguments[ofs] = (int *)_jit->x.pc;
    _jitl.types[ofs >> 5] &= ~(1 << (ofs & 31));
    if (jit_thumb_p())
	T2_STRWI(JIT_FTMP, JIT_SP, 0);
    else
	_STRI(JIT_FTMP, JIT_SP, 0);
}

__jit_inline void
swf_pusharg_d(jit_state_t _jit, jit_fpr_t r0)
{
    int		ofs = _jitl.nextarg_put++;
    assert(ofs < 256);
    _jitl.stack_offset -= sizeof(double);
    if (!jit_thumb_p() && jit_armv5e_p())
	_LDRDIN(JIT_TMP, JIT_FP, swf_off(r0) + 8);
    else {
	swf_ldrin(JIT_TMP, JIT_FP, swf_off(r0) + 8);
	swf_ldrin(JIT_FTMP, JIT_FP, swf_off(r0) + 4);
    }
    _jitl.arguments[ofs] = (int *)_jit->x.pc;
    _jitl.types[ofs >> 5] |= 1 << (ofs & 31);
    /* large offsets (handled by patch_arguments) cannot be encoded in STRDI */
    if (jit_thumb_p()) {
	T2_STRWI(JIT_TMP, JIT_SP, 0);
	T2_STRWI(JIT_FTMP, JIT_SP, 0);
    }
    else {
	_STRI(JIT_TMP, JIT_SP, 0);
	_STRI(JIT_FTMP, JIT_SP, 0);
    }
}

#define swf_retval_f(_jit, r0)		swf_strin(_R0, JIT_FP, swf_off(r0) + 8)
__jit_inline void
swf_retval_d(jit_state_t _jit, jit_fpr_t r0)
{
    if (!jit_thumb_p() && jit_armv5e_p())
	_STRDIN(_R0, JIT_FP, swf_off(r0) + 8);
    else {
	swf_strin(_R0, JIT_FP, swf_off(r0) + 8);
	swf_strin(_R1, JIT_FP, swf_off(r0) + 4);
    }
}
#endif
#endif /* __lightning_fp_swf_h */
