#include "jit-internal.h"
#include "jit-rules.h"
#include "jit-setjmp.h"
#if HAVE_STDLIB_H
# include <stdlib.h>
#endif
#if HAVE_ALLOCA_H
# include <alloca.h>
#endif
#ifdef JIT_WIN32_PLATFORM
# include <malloc.h>
# ifndef alloca
# define alloca _alloca
# endif
#endif
typedef struct
{
unsigned short ioper;
unsigned short iuoper;
unsigned short loper;
unsigned short luoper;
unsigned short foper;
unsigned short doper;
unsigned short nfoper;
void *ifunc;
const char *iname;
const jit_intrinsic_descr_t *idesc;
void *iufunc;
const char *iuname;
const jit_intrinsic_descr_t *iudesc;
void *lfunc;
const char *lname;
const jit_intrinsic_descr_t *ldesc;
void *lufunc;
const char *luname;
const jit_intrinsic_descr_t *ludesc;
void *ffunc;
const char *fname;
const jit_intrinsic_descr_t *fdesc;
void *dfunc;
const char *dname;
const jit_intrinsic_descr_t *ddesc;
void *nffunc;
const char *nfname;
const jit_intrinsic_descr_t *nfdesc;
} jit_opcode_descr;
#define jit_intrinsic(name, descr) (void *)name, #name, &descr
#define jit_no_intrinsic 0, 0, 0
static jit_intrinsic_descr_t const descr_i_ii = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_int_def,
(jit_type_t) &_jit_type_int_def
};
static jit_intrinsic_descr_t const descr_e_pi_ii = {
(jit_type_t) &_jit_type_int_def,
(jit_type_t) &_jit_type_int_def,
(jit_type_t) &_jit_type_int_def,
(jit_type_t) &_jit_type_int_def
};
static jit_intrinsic_descr_t const descr_i_iI = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_int_def,
(jit_type_t) &_jit_type_uint_def
};
static jit_intrinsic_descr_t const descr_i_i = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_int_def,
0
};
static jit_intrinsic_descr_t const descr_I_II = {
(jit_type_t) &_jit_type_uint_def,
0,
(jit_type_t) &_jit_type_uint_def,
(jit_type_t) &_jit_type_uint_def
};
static jit_intrinsic_descr_t const descr_e_pI_II = {
(jit_type_t) &_jit_type_int_def,
(jit_type_t) &_jit_type_uint_def,
(jit_type_t) &_jit_type_uint_def,
(jit_type_t) &_jit_type_uint_def
};
static jit_intrinsic_descr_t const descr_I_I = {
(jit_type_t) &_jit_type_uint_def,
0,
(jit_type_t) &_jit_type_uint_def,
0
};
static jit_intrinsic_descr_t const descr_i_II = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_uint_def,
(jit_type_t) &_jit_type_uint_def
};
static jit_intrinsic_descr_t const descr_l_ll = {
(jit_type_t) &_jit_type_long_def,
0,
(jit_type_t) &_jit_type_long_def,
(jit_type_t) &_jit_type_long_def
};
static jit_intrinsic_descr_t const descr_e_pl_ll = {
(jit_type_t) &_jit_type_int_def,
(jit_type_t) &_jit_type_long_def,
(jit_type_t) &_jit_type_long_def,
(jit_type_t) &_jit_type_long_def
};
static jit_intrinsic_descr_t const descr_l_lI = {
(jit_type_t) &_jit_type_long_def,
0,
(jit_type_t) &_jit_type_long_def,
(jit_type_t) &_jit_type_uint_def
};
static jit_intrinsic_descr_t const descr_l_l = {
(jit_type_t) &_jit_type_long_def,
0,
(jit_type_t) &_jit_type_long_def,
0
};
static jit_intrinsic_descr_t const descr_i_ll = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_long_def,
(jit_type_t) &_jit_type_long_def
};
static jit_intrinsic_descr_t const descr_i_l = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_long_def,
0
};
static jit_intrinsic_descr_t const descr_L_LL = {
(jit_type_t) &_jit_type_ulong_def,
0,
(jit_type_t) &_jit_type_ulong_def,
(jit_type_t) &_jit_type_ulong_def
};
static jit_intrinsic_descr_t const descr_e_pL_LL = {
(jit_type_t) &_jit_type_int_def,
(jit_type_t) &_jit_type_ulong_def,
(jit_type_t) &_jit_type_ulong_def,
(jit_type_t) &_jit_type_ulong_def
};
static jit_intrinsic_descr_t const descr_L_LI = {
(jit_type_t) &_jit_type_ulong_def,
0,
(jit_type_t) &_jit_type_ulong_def,
(jit_type_t) &_jit_type_uint_def
};
static jit_intrinsic_descr_t const descr_L_L = {
(jit_type_t) &_jit_type_ulong_def,
0,
(jit_type_t) &_jit_type_ulong_def,
0
};
static jit_intrinsic_descr_t const descr_i_LL = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_ulong_def,
(jit_type_t) &_jit_type_ulong_def
};
static jit_intrinsic_descr_t const descr_f_ff = {
(jit_type_t) &_jit_type_float32_def,
0,
(jit_type_t) &_jit_type_float32_def,
(jit_type_t) &_jit_type_float32_def
};
static jit_intrinsic_descr_t const descr_f_f = {
(jit_type_t) &_jit_type_float32_def,
0,
(jit_type_t) &_jit_type_float32_def,
0
};
static jit_intrinsic_descr_t const descr_i_ff = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_float32_def,
(jit_type_t) &_jit_type_float32_def
};
static jit_intrinsic_descr_t const descr_i_f = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_float32_def,
0
};
static jit_intrinsic_descr_t const descr_d_dd = {
(jit_type_t) &_jit_type_float64_def,
0,
(jit_type_t) &_jit_type_float64_def,
(jit_type_t) &_jit_type_float64_def
};
static jit_intrinsic_descr_t const descr_d_d = {
(jit_type_t) &_jit_type_float64_def,
0,
(jit_type_t) &_jit_type_float64_def,
0
};
static jit_intrinsic_descr_t const descr_i_dd = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_float64_def,
(jit_type_t) &_jit_type_float64_def
};
static jit_intrinsic_descr_t const descr_i_d = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_float64_def,
0
};
static jit_intrinsic_descr_t const descr_D_DD = {
(jit_type_t) &_jit_type_nfloat_def,
0,
(jit_type_t) &_jit_type_nfloat_def,
(jit_type_t) &_jit_type_nfloat_def
};
static jit_intrinsic_descr_t const descr_D_D = {
(jit_type_t) &_jit_type_nfloat_def,
0,
(jit_type_t) &_jit_type_nfloat_def,
0
};
static jit_intrinsic_descr_t const descr_i_DD = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_nfloat_def,
(jit_type_t) &_jit_type_nfloat_def
};
static jit_intrinsic_descr_t const descr_i_D = {
(jit_type_t) &_jit_type_int_def,
0,
(jit_type_t) &_jit_type_nfloat_def,
0
};
static jit_value_t
apply_unary(jit_function_t func, int oper, jit_value_t value, jit_type_t type)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_value_t dest = jit_value_create(func, type);
if(!dest)
{
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) oper;
insn->dest = dest;
insn->value1 = value;
jit_value_ref(func, value);
return dest;
}
static jit_value_t
apply_binary(jit_function_t func, int oper, jit_value_t value1, jit_value_t value2,
jit_type_t type)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_value_t dest = jit_value_create(func, type);
if(!dest)
{
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) oper;
insn->dest = dest;
insn->value1 = value1;
jit_value_ref(func, value1);
insn->value2 = value2;
jit_value_ref(func, value2);
return dest;
}
static int
apply_ternary(jit_function_t func, int oper, jit_value_t value1, jit_value_t value2,
jit_value_t value3)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) oper;
insn->flags = JIT_INSN_DEST_IS_VALUE;
insn->dest = value1;
jit_value_ref(func, value1);
insn->value1 = value2;
jit_value_ref(func, value2);
insn->value2 = value3;
jit_value_ref(func, value3);
return 1;
}
static int
create_note(jit_function_t func, int oper, jit_value_t value1, jit_value_t value2)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) oper;
insn->value1 = value1;
jit_value_ref(func, value1);
insn->value2 = value2;
jit_value_ref(func, value2);
return 1;
}
static int
create_unary_note(jit_function_t func, int oper, jit_value_t value)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) oper;
insn->value1 = value;
jit_value_ref(func, value);
return 1;
}
static int
create_noarg_note(jit_function_t func, int oper)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) oper;
return 1;
}
static jit_value_t
create_dest_note(jit_function_t func, int oper, jit_type_t type)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_value_t dest = jit_value_create(func, type);
if(!dest)
{
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) oper;
insn->dest = dest;
return dest;
}
static jit_type_t
common_binary(jit_type_t type1, jit_type_t type2, int int_only, int float_only)
{
type1 = jit_type_promote_int(jit_type_normalize(type1));
type2 = jit_type_promote_int(jit_type_normalize(type2));
if(!float_only)
{
if(type1 == jit_type_int)
{
if(type2 == jit_type_int || type2 == jit_type_uint)
{
return jit_type_int;
}
else if(type2 == jit_type_long || type2 == jit_type_ulong)
{
return jit_type_long;
}
}
else if(type1 == jit_type_uint)
{
if(type2 == jit_type_int || type2 == jit_type_uint ||
type2 == jit_type_long || type2 == jit_type_ulong)
{
return type2;
}
}
else if(type1 == jit_type_long)
{
if(type2 == jit_type_int || type2 == jit_type_uint ||
type2 == jit_type_long || type2 == jit_type_ulong)
{
return jit_type_long;
}
}
else if(type1 == jit_type_ulong)
{
if(type2 == jit_type_int || type2 == jit_type_long)
{
return jit_type_long;
}
else if(type2 == jit_type_uint || type2 == jit_type_ulong)
{
return jit_type_ulong;
}
}
if(int_only)
{
return jit_type_long;
}
}
if(type1 == jit_type_nfloat || type2 == jit_type_nfloat)
{
return jit_type_nfloat;
}
else if(type1 == jit_type_float64 || type2 == jit_type_float64)
{
return jit_type_float64;
}
else if(type1 == jit_type_float32 || type2 == jit_type_float32)
{
return jit_type_float32;
}
else
{
return jit_type_nfloat;
}
}
static jit_value_t
apply_intrinsic(jit_function_t func, const jit_opcode_descr *descr,
jit_value_t value1, jit_value_t value2, jit_type_t type)
{
switch (type->kind)
{
default:
case JIT_TYPE_INT:
return jit_insn_call_intrinsic(func, descr->iname,
descr->ifunc, descr->idesc,
value1, value2);
case JIT_TYPE_UINT:
return jit_insn_call_intrinsic(func, descr->iuname,
descr->iufunc, descr->iudesc,
value1, value2);
case JIT_TYPE_LONG:
return jit_insn_call_intrinsic(func, descr->lname,
descr->lfunc, descr->ldesc,
value1, value2);
case JIT_TYPE_ULONG:
return jit_insn_call_intrinsic(func, descr->luname,
descr->lufunc, descr->ludesc,
value1, value2);
case JIT_TYPE_FLOAT32:
return jit_insn_call_intrinsic(func, descr->fname,
descr->ffunc, descr->fdesc,
value1, value2);
case JIT_TYPE_FLOAT64:
return jit_insn_call_intrinsic(func, descr->dname,
descr->dfunc, descr->ddesc,
value1, value2);
case JIT_TYPE_NFLOAT:
return jit_insn_call_intrinsic(func, descr->nfname,
descr->nffunc, descr->nfdesc,
value1, value2);
}
}
static jit_value_t
apply_unary_arith(jit_function_t func, const jit_opcode_descr *descr,
jit_value_t value, int int_only, int float_only,
int overflow_check)
{
jit_type_t type = common_binary(value->type, value->type, int_only, float_only);
int oper;
const jit_intrinsic_descr_t *desc;
switch (type->kind)
{
default:
case JIT_TYPE_INT:
oper = descr->ioper;
desc = descr->idesc;
break;
case JIT_TYPE_UINT:
oper = descr->iuoper;
desc = descr->iudesc;
break;
case JIT_TYPE_LONG:
oper = descr->loper;
desc = descr->ldesc;
break;
case JIT_TYPE_ULONG:
oper = descr->luoper;
desc = descr->ludesc;
break;
case JIT_TYPE_FLOAT32:
oper = descr->foper;
desc = descr->fdesc;
break;
case JIT_TYPE_FLOAT64:
oper = descr->doper;
desc = descr->ddesc;
break;
case JIT_TYPE_NFLOAT:
oper = descr->nfoper;
desc = descr->nfdesc;
break;
}
value = jit_insn_convert(func, value, type, overflow_check);
if(!value)
{
return 0;
}
if(jit_value_is_constant(value))
{
jit_value_t result = _jit_opcode_apply_unary(func, oper, value, type);
if(result)
{
return result;
}
}
if(desc && desc->ptr_result_type)
{
func->builder->may_throw = 1;
}
if(!_jit_opcode_is_supported(oper))
{
return apply_intrinsic(func, descr, value, 0, type);
}
return apply_unary(func, oper, value, type);
}
static jit_value_t
apply_arith(jit_function_t func, const jit_opcode_descr *descr,
jit_value_t value1, jit_value_t value2,
int int_only, int float_only, int overflow_check)
{
jit_type_t type = common_binary(value1->type, value2->type, int_only, float_only);
int oper;
const jit_intrinsic_descr_t *desc;
switch (type->kind)
{
default:
case JIT_TYPE_INT:
oper = descr->ioper;
desc = descr->idesc;
break;
case JIT_TYPE_UINT:
oper = descr->iuoper;
desc = descr->iudesc;
break;
case JIT_TYPE_LONG:
oper = descr->loper;
desc = descr->ldesc;
break;
case JIT_TYPE_ULONG:
oper = descr->luoper;
desc = descr->ludesc;
break;
case JIT_TYPE_FLOAT32:
oper = descr->foper;
desc = descr->fdesc;
break;
case JIT_TYPE_FLOAT64:
oper = descr->doper;
desc = descr->ddesc;
break;
case JIT_TYPE_NFLOAT:
oper = descr->nfoper;
desc = descr->nfdesc;
break;
}
value1 = jit_insn_convert(func, value1, type, overflow_check);
value2 = jit_insn_convert(func, value2, type, overflow_check);
if(!value1 || !value2)
{
return 0;
}
if(jit_value_is_constant(value1) && jit_value_is_constant(value2))
{
jit_value_t result = _jit_opcode_apply(func, oper, value1, value2, type);
if(result)
{
return result;
}
}
if(desc && desc->ptr_result_type)
{
func->builder->may_throw = 1;
}
if(!_jit_opcode_is_supported(oper))
{
return apply_intrinsic(func, descr, value1, value2, type);
}
return apply_binary(func, oper, value1, value2, type);
}
static jit_value_t
apply_shift(jit_function_t func, const jit_opcode_descr *descr,
jit_value_t value1, jit_value_t value2)
{
jit_type_t type = common_binary(value1->type, value1->type, 1, 0);
int oper;
switch (type->kind)
{
case JIT_TYPE_INT:
oper = descr->ioper;
break;
case JIT_TYPE_UINT:
oper = descr->iuoper;
break;
case JIT_TYPE_LONG:
oper = descr->loper;
break;
default:
case JIT_TYPE_ULONG:
oper = descr->luoper;
break;
}
jit_type_t count_type = jit_type_promote_int(jit_type_normalize(value2->type));
if(count_type != jit_type_int)
{
count_type = jit_type_uint;
}
value1 = jit_insn_convert(func, value1, type, 0);
value2 = jit_insn_convert(func, value2, count_type, 0);
if(!value1 || !value2)
{
return 0;
}
if(jit_value_is_constant(value1) && jit_value_is_constant(value2))
{
jit_value_t result = _jit_opcode_apply(func, oper, value1, value2, type);
if(result)
{
return result;
}
}
if(!_jit_opcode_is_supported(oper))
{
return apply_intrinsic(func, descr, value1, value2, type);
}
return apply_binary(func, oper, value1, value2, type);
}
static jit_value_t
apply_compare(jit_function_t func, const jit_opcode_descr *descr,
jit_value_t value1, jit_value_t value2, int float_only)
{
jit_type_t type = common_binary(value1->type, value2->type, 0, float_only);
int oper;
switch (type->kind)
{
default:
case JIT_TYPE_INT:
oper = descr->ioper;
break;
case JIT_TYPE_UINT:
oper = descr->iuoper;
break;
case JIT_TYPE_LONG:
oper = descr->loper;
break;
case JIT_TYPE_ULONG:
oper = descr->luoper;
break;
case JIT_TYPE_FLOAT32:
oper = descr->foper;
break;
case JIT_TYPE_FLOAT64:
oper = descr->doper;
break;
case JIT_TYPE_NFLOAT:
oper = descr->nfoper;
break;
}
value1 = jit_insn_convert(func, value1, type, 0);
value2 = jit_insn_convert(func, value2, type, 0);
if(!value1 || !value2)
{
return 0;
}
if(jit_value_is_constant(value1) && jit_value_is_constant(value2))
{
jit_value_t result = _jit_opcode_apply(func, oper, value1, value2, jit_type_int);
if(result)
{
return result;
}
}
if(!_jit_opcode_is_supported(oper))
{
return apply_intrinsic(func, descr, value1, value2, type);
}
return apply_binary(func, oper, value1, value2, jit_type_int);
}
static jit_value_t
test_float_value(jit_function_t func, const jit_opcode_descr *descr, jit_value_t value)
{
jit_type_t type = jit_type_normalize(value->type);
int oper;
if(type == jit_type_float32)
{
oper = descr->foper;
}
else if(type == jit_type_float64)
{
oper = descr->doper;
}
else if(type == jit_type_nfloat)
{
oper = descr->nfoper;
}
else
{
return jit_value_create_nint_constant(func, jit_type_int, 0);
}
if(!_jit_opcode_is_supported(oper))
{
return apply_intrinsic(func, descr, value, 0, type);
}
return apply_unary(func, oper, value, jit_type_int);
}
int
jit_insn_get_opcode(jit_insn_t insn)
{
return insn->opcode;
}
jit_value_t
jit_insn_get_dest(jit_insn_t insn)
{
if((insn->flags & JIT_INSN_DEST_OTHER_FLAGS) != 0)
{
return 0;
}
return insn->dest;
}
jit_value_t
jit_insn_get_value1(jit_insn_t insn)
{
if((insn->flags & JIT_INSN_VALUE1_OTHER_FLAGS) != 0)
{
return 0;
}
return insn->value1;
}
jit_value_t
jit_insn_get_value2(jit_insn_t insn)
{
if((insn->flags & JIT_INSN_VALUE2_OTHER_FLAGS) != 0)
{
return 0;
}
return insn->value2;
}
jit_label_t
jit_insn_get_label(jit_insn_t insn)
{
if((insn->flags & JIT_INSN_DEST_IS_LABEL) != 0)
{
return (jit_label_t) insn->dest;
}
if((insn->flags & JIT_INSN_VALUE1_IS_LABEL) != 0)
{
return (jit_label_t) insn->value1;
}
return 0;
}
jit_function_t
jit_insn_get_function(jit_insn_t insn)
{
if((insn->flags & JIT_INSN_DEST_IS_FUNCTION) == 0)
{
return 0;
}
return (jit_function_t) insn->dest;
}
void *
jit_insn_get_native(jit_insn_t insn)
{
if((insn->flags & JIT_INSN_DEST_IS_NATIVE) == 0)
{
return 0;
}
return (void *) insn->dest;
}
const char *
jit_insn_get_name(jit_insn_t insn)
{
if((insn->flags & JIT_INSN_VALUE1_IS_NAME) == 0)
{
return 0;
}
return (const char *) insn->value1;
}
jit_type_t
jit_insn_get_signature(jit_insn_t insn)
{
if((insn->flags & JIT_INSN_VALUE2_IS_SIGNATURE) == 0)
{
return 0;
}
return (jit_type_t) insn->value2;
}
int
jit_insn_dest_is_value(jit_insn_t insn)
{
return (insn->flags & JIT_INSN_DEST_IS_VALUE) != 0;
}
static int
new_block_with_label(jit_function_t func, jit_label_t *label, int force_new_block)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
jit_block_t block;
jit_block_t current_block = func->builder->current_block;
if(force_new_block || _jit_block_get_last(current_block))
{
block = _jit_block_create(func);
if(!block)
{
return 0;
}
}
else
{
block = current_block;
if(block->label != jit_label_undefined && *label == jit_label_undefined)
{
*label = block->label;
return 1;
}
}
if(*label == jit_label_undefined)
{
*label = func->builder->next_label++;
}
if(!_jit_block_record_label(block, *label))
{
_jit_block_destroy(block);
return 0;
}
if(block != current_block)
{
_jit_block_attach_before(func->builder->exit_block, block, block);
func->builder->current_block = block;
}
return 1;
}
int
jit_insn_label(jit_function_t func, jit_label_t *label)
{
return new_block_with_label(func, label, 1);
}
int
jit_insn_label_tight(jit_function_t func, jit_label_t *label)
{
return new_block_with_label(func, label, 0);
}
int
jit_insn_new_block(jit_function_t func)
{
jit_block_t block = _jit_block_create(func);
if(!block)
{
return 0;
}
#ifdef _JIT_BLOCK_DEBUG
jit_label_t label = func->builder->next_label++;
if(!_jit_block_record_label(block, label))
{
_jit_block_destroy(block);
return 0;
}
#endif
_jit_block_attach_before(func->builder->exit_block, block, block);
func->builder->current_block = block;
return 1;
}
int
_jit_load_opcode(int base_opcode, jit_type_t type)
{
type = jit_type_normalize(type);
if(!type)
{
return 0;
}
switch(type->kind)
{
case JIT_TYPE_SBYTE:
return base_opcode;
case JIT_TYPE_UBYTE:
return base_opcode + 1;
case JIT_TYPE_SHORT:
return base_opcode + 2;
case JIT_TYPE_USHORT:
return base_opcode + 3;
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
return base_opcode + 4;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
return base_opcode + 5;
case JIT_TYPE_FLOAT32:
return base_opcode + 6;
case JIT_TYPE_FLOAT64:
return base_opcode + 7;
case JIT_TYPE_NFLOAT:
return base_opcode + 8;
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
return base_opcode + 9;
}
return 0;
}
int
_jit_store_opcode(int base_opcode, int small_base, jit_type_t type)
{
if(small_base)
{
base_opcode -= 2;
}
else
{
small_base = base_opcode;
}
type = jit_type_normalize(type);
switch(type->kind)
{
case JIT_TYPE_SBYTE:
case JIT_TYPE_UBYTE:
return small_base;
case JIT_TYPE_SHORT:
case JIT_TYPE_USHORT:
return small_base + 1;
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
return base_opcode + 2;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
return base_opcode + 3;
case JIT_TYPE_FLOAT32:
return base_opcode + 4;
case JIT_TYPE_FLOAT64:
return base_opcode + 5;
case JIT_TYPE_NFLOAT:
return base_opcode + 6;
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
return base_opcode + 7;
default:
return base_opcode + 2;
}
}
int
jit_insn_nop(jit_function_t func)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = JIT_OP_NOP;
return 1;
}
jit_value_t
jit_insn_load(jit_function_t func, jit_value_t value)
{
if(value->is_constant)
{
return value;
}
int opcode = _jit_load_opcode(JIT_OP_COPY_LOAD_SBYTE, value->type);
if(opcode == 0)
{
return 0;
}
return apply_unary(func, opcode, value, value->type);
}
jit_value_t
jit_insn_dup(jit_function_t func, jit_value_t value)
{
return jit_insn_load(func, value);
}
int
jit_insn_store(jit_function_t func, jit_value_t dest, jit_value_t value)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
value = jit_insn_convert(func, value, dest->type, 0);
if(!value)
{
return 0;
}
int opcode = _jit_store_opcode(JIT_OP_COPY_INT, JIT_OP_COPY_STORE_BYTE, dest->type);
if(opcode == 0)
{
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) opcode;
insn->dest = dest;
jit_value_ref(func, dest);
insn->value1 = value;
jit_value_ref(func, value);
return 1;
}
static jit_insn_t
find_base_insn(jit_function_t func, jit_insn_iter_t iter, jit_value_t value, int *plast)
{
if(value->is_addressable || value->is_volatile)
{
return 0;
}
int last = 1;
jit_insn_t insn;
while((insn = jit_insn_iter_previous(&iter)) != 0)
{
if(insn->dest == value)
{
if(insn->opcode == JIT_OP_ADDRESS_OF)
{
*plast = last;
return insn;
}
if(insn->opcode == JIT_OP_ADD_RELATIVE)
{
value = insn->value1;
if(value->is_addressable || value->is_volatile)
{
return 0;
}
jit_insn_iter_t iter2 = iter;
jit_insn_iter_next(&iter2);
jit_insn_t insn2;
while((insn2 = jit_insn_iter_next(&iter2)) != 0)
{
if(insn2->dest == value
&& (insn2->flags & JIT_INSN_DEST_IS_VALUE) == 0)
{
return 0;
}
}
*plast = last;
return insn;
}
if((insn->flags & JIT_INSN_DEST_IS_VALUE) == 0)
{
break;
}
}
last = 0;
}
return 0;
}
jit_value_t
jit_insn_load_relative(jit_function_t func, jit_value_t value, jit_nint offset, jit_type_t type)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_insn_iter_t iter;
jit_insn_iter_init_last(&iter, func->builder->current_block);
int last;
jit_insn_t insn = find_base_insn(func, iter, value, &last);
if(insn && insn->opcode == JIT_OP_ADD_RELATIVE)
{
offset += jit_value_get_nint_constant(insn->value2);
value = insn->value1;
insn = find_base_insn(func, iter, value, &last);
last = 0;
}
if(insn && insn->opcode == JIT_OP_ADDRESS_OF && !last)
{
value = jit_insn_address_of(func, insn->value1);
if(!value)
{
return 0;
}
}
int opcode = _jit_load_opcode(JIT_OP_LOAD_RELATIVE_SBYTE, type);
if(opcode == 0)
{
return 0;
}
jit_value_t offset_value = jit_value_create_nint_constant(func, jit_type_nint, offset);
if(!offset_value)
{
return 0;
}
return apply_binary(func, opcode, value, offset_value, type);
}
int
jit_insn_store_relative(jit_function_t func, jit_value_t dest, jit_nint offset, jit_value_t value)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_insn_iter_t iter;
jit_insn_iter_init_last(&iter, func->builder->current_block);
int last;
jit_insn_t insn = find_base_insn(func, iter, dest, &last);
if(insn && insn->opcode == JIT_OP_ADD_RELATIVE)
{
offset += jit_value_get_nint_constant(insn->value2);
dest = insn->value1;
insn = find_base_insn(func, iter, value, &last);
last = 0;
}
if(insn && insn->opcode == JIT_OP_ADDRESS_OF && !last)
{
dest = jit_insn_address_of(func, insn->value1);
if(!dest)
{
return 0;
}
}
int opcode = _jit_store_opcode(JIT_OP_STORE_RELATIVE_BYTE, 0, value->type);
if(opcode == 0)
{
return 0;
}
jit_value_t offset_value = jit_value_create_nint_constant(func, jit_type_nint, offset);
if(!offset_value)
{
return 0;
}
insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) opcode;
insn->flags = JIT_INSN_DEST_IS_VALUE;
insn->dest = dest;
jit_value_ref(func, dest);
insn->value1 = value;
jit_value_ref(func, value);
insn->value2 = offset_value;
return 1;
}
jit_value_t
jit_insn_add_relative(jit_function_t func, jit_value_t value, jit_nint offset)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_insn_iter_t iter;
jit_insn_iter_init_last(&iter, func->builder->current_block);
int last;
jit_insn_t insn = find_base_insn(func, iter, value, &last);
if(insn && insn->opcode == JIT_OP_ADD_RELATIVE)
{
offset += jit_value_get_nint_constant(insn->value2);
value = insn->value1;
}
jit_value_t offset_value = jit_value_create_nint_constant(func, jit_type_nint, offset);
if(!offset_value)
{
return 0;
}
return apply_binary(func, JIT_OP_ADD_RELATIVE, value, offset_value, jit_type_void_ptr);
}
static jit_value_t
element_address(jit_function_t func, jit_value_t base, jit_value_t index, jit_nint size)
{
jit_value_t offset_value = jit_value_create_nint_constant(func, jit_type_nint, size);
if(!offset_value)
{
return 0;
}
offset_value = jit_insn_mul(func, index, offset_value);
if(!offset_value)
{
return 0;
}
return jit_insn_add(func, base, offset_value);
}
jit_value_t
jit_insn_load_elem(jit_function_t func, jit_value_t base_addr, jit_value_t index,
jit_type_t elem_type)
{
jit_nint size = (jit_nint) jit_type_get_size(elem_type);
index = jit_insn_convert(func, index, jit_type_nint, 0);
if(!index)
{
return 0;
}
if(jit_value_is_constant(index))
{
size *= jit_value_get_nint_constant(index);
return jit_insn_load_relative(func, base_addr, size, elem_type);
}
int opcode = _jit_load_opcode(JIT_OP_LOAD_ELEMENT_SBYTE, elem_type);
if(opcode != 0 && opcode != (JIT_OP_LOAD_ELEMENT_SBYTE + 9))
{
return apply_binary(func, opcode, base_addr, index, elem_type);
}
jit_value_t addr = element_address(func, base_addr, index, size);
if(!addr)
{
return 0;
}
return jit_insn_load_relative(func, addr, 0, elem_type);
}
jit_value_t
jit_insn_load_elem_address(jit_function_t func, jit_value_t base_addr, jit_value_t index,
jit_type_t elem_type)
{
jit_nint size = (jit_nint) jit_type_get_size(elem_type);
index = jit_insn_convert(func, index, jit_type_nint, 0);
if(!index)
{
return 0;
}
return element_address(func, base_addr, index, size);
}
int
jit_insn_store_elem(jit_function_t func, jit_value_t base_addr, jit_value_t index,
jit_value_t value)
{
jit_type_t elem_type = jit_value_get_type(value);
jit_nint size = (jit_nint) jit_type_get_size(elem_type);
index = jit_insn_convert(func, index, jit_type_nint, 0);
if(!index)
{
return 0;
}
if(jit_value_is_constant(index))
{
return jit_insn_store_relative(func, base_addr,
jit_value_get_nint_constant(index) * size,
value);
}
int opcode = _jit_store_opcode(JIT_OP_STORE_ELEMENT_BYTE, 0, elem_type);
if(opcode != 0 && opcode != (JIT_OP_STORE_ELEMENT_BYTE + 7))
{
return apply_ternary(func, opcode, base_addr, index, value);
}
jit_value_t addr = element_address(func, base_addr, index, size);
if(!addr)
{
return 0;
}
return jit_insn_store_relative(func, addr, 0, value);
}
int
jit_insn_check_null(jit_function_t func, jit_value_t value)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(value->is_nint_constant && value->address != 0)
{
return 1;
}
func->builder->may_throw = 1;
return create_unary_note(func, JIT_OP_CHECK_NULL, value);
}
int
_jit_insn_check_is_redundant(const jit_insn_iter_t *iter)
{
jit_insn_iter_t new_iter = *iter;
jit_insn_t insn = jit_insn_iter_previous(&new_iter);
jit_value_t value = insn->value1;
if(!value->is_temporary || !value->is_local)
{
return 0;
}
if(value->is_volatile || value->is_addressable)
{
return 0;
}
while((insn = jit_insn_iter_previous(&new_iter)) != 0)
{
if(insn->opcode == JIT_OP_CHECK_NULL && insn->value1 == value)
{
return 1;
}
if(insn->opcode >= JIT_OP_STORE_RELATIVE_BYTE &&
insn->opcode <= JIT_OP_STORE_RELATIVE_STRUCT)
{
continue;
}
if(insn->dest == value)
{
return 0;
}
}
return 0;
}
jit_value_t
jit_insn_add(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const add_descr = {
JIT_OP_IADD,
JIT_OP_IADD,
JIT_OP_LADD,
JIT_OP_LADD,
JIT_OP_FADD,
JIT_OP_DADD,
JIT_OP_NFADD,
jit_intrinsic(jit_int_add, descr_i_ii),
jit_intrinsic(jit_uint_add, descr_I_II),
jit_intrinsic(jit_long_add, descr_l_ll),
jit_intrinsic(jit_ulong_add, descr_L_LL),
jit_intrinsic(jit_float32_add, descr_f_ff),
jit_intrinsic(jit_float64_add, descr_d_dd),
jit_intrinsic(jit_nfloat_add, descr_D_DD)
};
return apply_arith(func, &add_descr, value1, value2, 0, 0, 0);
}
jit_value_t
jit_insn_add_ovf(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const add_ovf_descr = {
JIT_OP_IADD_OVF,
JIT_OP_IADD_OVF_UN,
JIT_OP_LADD_OVF,
JIT_OP_LADD_OVF_UN,
JIT_OP_FADD,
JIT_OP_DADD,
JIT_OP_NFADD,
jit_intrinsic(jit_int_add_ovf, descr_e_pi_ii),
jit_intrinsic(jit_uint_add_ovf, descr_e_pI_II),
jit_intrinsic(jit_long_add_ovf, descr_e_pl_ll),
jit_intrinsic(jit_ulong_add_ovf, descr_e_pL_LL),
jit_intrinsic(jit_float32_add, descr_f_ff),
jit_intrinsic(jit_float64_add, descr_d_dd),
jit_intrinsic(jit_nfloat_add, descr_D_DD)
};
return apply_arith(func, &add_ovf_descr, value1, value2, 0, 0, 1);
}
jit_value_t
jit_insn_sub(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const sub_descr = {
JIT_OP_ISUB,
JIT_OP_ISUB,
JIT_OP_LSUB,
JIT_OP_LSUB,
JIT_OP_FSUB,
JIT_OP_DSUB,
JIT_OP_NFSUB,
jit_intrinsic(jit_int_sub, descr_i_ii),
jit_intrinsic(jit_uint_sub, descr_I_II),
jit_intrinsic(jit_long_sub, descr_l_ll),
jit_intrinsic(jit_ulong_sub, descr_L_LL),
jit_intrinsic(jit_float32_sub, descr_f_ff),
jit_intrinsic(jit_float64_sub, descr_d_dd),
jit_intrinsic(jit_nfloat_sub, descr_D_DD)
};
return apply_arith(func, &sub_descr, value1, value2, 0, 0, 0);
}
jit_value_t
jit_insn_sub_ovf(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const sub_ovf_descr = {
JIT_OP_ISUB_OVF,
JIT_OP_ISUB_OVF_UN,
JIT_OP_LSUB_OVF,
JIT_OP_LSUB_OVF_UN,
JIT_OP_FSUB,
JIT_OP_DSUB,
JIT_OP_NFSUB,
jit_intrinsic(jit_int_sub_ovf, descr_e_pi_ii),
jit_intrinsic(jit_uint_sub_ovf, descr_e_pI_II),
jit_intrinsic(jit_long_sub_ovf, descr_e_pl_ll),
jit_intrinsic(jit_ulong_sub_ovf, descr_e_pL_LL),
jit_intrinsic(jit_float32_sub, descr_f_ff),
jit_intrinsic(jit_float64_sub, descr_d_dd),
jit_intrinsic(jit_nfloat_sub, descr_D_DD)
};
return apply_arith(func, &sub_ovf_descr, value1, value2, 0, 0, 1);
}
jit_value_t
jit_insn_mul(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const mul_descr = {
JIT_OP_IMUL,
JIT_OP_IMUL,
JIT_OP_LMUL,
JIT_OP_LMUL,
JIT_OP_FMUL,
JIT_OP_DMUL,
JIT_OP_NFMUL,
jit_intrinsic(jit_int_mul, descr_i_ii),
jit_intrinsic(jit_uint_mul, descr_I_II),
jit_intrinsic(jit_long_mul, descr_l_ll),
jit_intrinsic(jit_ulong_mul, descr_L_LL),
jit_intrinsic(jit_float32_mul, descr_f_ff),
jit_intrinsic(jit_float64_mul, descr_d_dd),
jit_intrinsic(jit_nfloat_mul, descr_D_DD)
};
return apply_arith(func, &mul_descr, value1, value2, 0, 0, 0);
}
jit_value_t
jit_insn_mul_ovf(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const mul_ovf_descr = {
JIT_OP_IMUL_OVF,
JIT_OP_IMUL_OVF_UN,
JIT_OP_LMUL_OVF,
JIT_OP_LMUL_OVF_UN,
JIT_OP_FMUL,
JIT_OP_DMUL,
JIT_OP_NFMUL,
jit_intrinsic(jit_int_mul_ovf, descr_e_pi_ii),
jit_intrinsic(jit_uint_mul_ovf, descr_e_pI_II),
jit_intrinsic(jit_long_mul_ovf, descr_e_pl_ll),
jit_intrinsic(jit_ulong_mul_ovf, descr_e_pL_LL),
jit_intrinsic(jit_float32_mul, descr_f_ff),
jit_intrinsic(jit_float64_mul, descr_d_dd),
jit_intrinsic(jit_nfloat_mul, descr_D_DD)
};
return apply_arith(func, &mul_ovf_descr, value1, value2, 0, 0, 1);
}
jit_value_t
jit_insn_div(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const div_descr = {
JIT_OP_IDIV,
JIT_OP_IDIV_UN,
JIT_OP_LDIV,
JIT_OP_LDIV_UN,
JIT_OP_FDIV,
JIT_OP_DDIV,
JIT_OP_NFDIV,
jit_intrinsic(jit_int_div, descr_e_pi_ii),
jit_intrinsic(jit_uint_div, descr_e_pI_II),
jit_intrinsic(jit_long_div, descr_e_pl_ll),
jit_intrinsic(jit_ulong_div, descr_e_pL_LL),
jit_intrinsic(jit_float32_div, descr_f_ff),
jit_intrinsic(jit_float64_div, descr_d_dd),
jit_intrinsic(jit_nfloat_div, descr_D_DD)
};
return apply_arith(func, &div_descr, value1, value2, 0, 0, 0);
}
jit_value_t
jit_insn_rem(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const rem_descr = {
JIT_OP_IREM,
JIT_OP_IREM_UN,
JIT_OP_LREM,
JIT_OP_LREM_UN,
JIT_OP_FREM,
JIT_OP_DREM,
JIT_OP_NFREM,
jit_intrinsic(jit_int_rem, descr_e_pi_ii),
jit_intrinsic(jit_uint_rem, descr_e_pI_II),
jit_intrinsic(jit_long_rem, descr_e_pl_ll),
jit_intrinsic(jit_ulong_rem, descr_e_pL_LL),
jit_intrinsic(jit_float32_rem, descr_f_ff),
jit_intrinsic(jit_float64_rem, descr_d_dd),
jit_intrinsic(jit_nfloat_rem, descr_D_DD)
};
return apply_arith(func, &rem_descr, value1, value2, 0, 0, 0);
}
jit_value_t
jit_insn_rem_ieee(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const rem_ieee_descr = {
JIT_OP_IREM,
JIT_OP_IREM_UN,
JIT_OP_LREM,
JIT_OP_LREM_UN,
JIT_OP_FREM_IEEE,
JIT_OP_DREM_IEEE,
JIT_OP_NFREM_IEEE,
jit_intrinsic(jit_int_rem, descr_e_pi_ii),
jit_intrinsic(jit_uint_rem, descr_e_pI_II),
jit_intrinsic(jit_long_rem, descr_e_pl_ll),
jit_intrinsic(jit_ulong_rem, descr_e_pL_LL),
jit_intrinsic(jit_float32_ieee_rem, descr_f_ff),
jit_intrinsic(jit_float64_ieee_rem, descr_d_dd),
jit_intrinsic(jit_nfloat_ieee_rem, descr_D_DD)
};
return apply_arith(func, &rem_ieee_descr, value1, value2, 0, 0, 0);
}
jit_value_t
jit_insn_neg(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const neg_descr = {
JIT_OP_INEG,
JIT_OP_INEG,
JIT_OP_LNEG,
JIT_OP_LNEG,
JIT_OP_FNEG,
JIT_OP_DNEG,
JIT_OP_NFNEG,
jit_intrinsic(jit_int_neg, descr_i_i),
jit_intrinsic(jit_uint_neg, descr_I_I),
jit_intrinsic(jit_long_neg, descr_l_l),
jit_intrinsic(jit_ulong_neg, descr_L_L),
jit_intrinsic(jit_float32_neg, descr_f_f),
jit_intrinsic(jit_float64_neg, descr_d_d),
jit_intrinsic(jit_nfloat_neg, descr_D_D)
};
jit_type_t type = jit_type_promote_int(jit_type_normalize(value->type));
int oper;
switch (type->kind)
{
default:
case JIT_TYPE_INT:
oper = neg_descr.ioper;
break;
case JIT_TYPE_UINT:
type = jit_type_int;
oper = neg_descr.ioper;
break;
case JIT_TYPE_LONG:
oper = neg_descr.loper;
break;
case JIT_TYPE_ULONG:
type = jit_type_long;
oper = neg_descr.loper;
break;
case JIT_TYPE_FLOAT32:
oper = neg_descr.foper;
break;
case JIT_TYPE_FLOAT64:
oper = neg_descr.doper;
break;
case JIT_TYPE_NFLOAT:
oper = neg_descr.nfoper;
break;
}
value = jit_insn_convert(func, value, type, 0);
if(!value)
{
return 0;
}
if(jit_value_is_constant(value))
{
jit_value_t result = _jit_opcode_apply_unary(func, oper, value, type);
if(result)
{
return result;
}
}
if(!_jit_opcode_is_supported(oper))
{
return apply_intrinsic(func, &neg_descr, value, 0, type);
}
return apply_unary(func, oper, value, type);
}
jit_value_t
jit_insn_and(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const and_descr = {
JIT_OP_IAND,
JIT_OP_IAND,
JIT_OP_LAND,
JIT_OP_LAND,
0, 0, 0,
jit_intrinsic(jit_int_and, descr_i_ii),
jit_intrinsic(jit_uint_and, descr_I_II),
jit_intrinsic(jit_long_and, descr_l_ll),
jit_intrinsic(jit_ulong_and, descr_L_LL),
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic
};
return apply_arith(func, &and_descr, value1, value2, 1, 0, 0);
}
jit_value_t
jit_insn_or(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const or_descr = {
JIT_OP_IOR,
JIT_OP_IOR,
JIT_OP_LOR,
JIT_OP_LOR,
0, 0, 0,
jit_intrinsic(jit_int_or, descr_i_ii),
jit_intrinsic(jit_uint_or, descr_I_II),
jit_intrinsic(jit_long_or, descr_l_ll),
jit_intrinsic(jit_ulong_or, descr_L_LL),
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic
};
return apply_arith(func, &or_descr, value1, value2, 1, 0, 0);
}
jit_value_t
jit_insn_xor(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const xor_descr = {
JIT_OP_IXOR,
JIT_OP_IXOR,
JIT_OP_LXOR,
JIT_OP_LXOR,
0, 0, 0,
jit_intrinsic(jit_int_xor, descr_i_ii),
jit_intrinsic(jit_uint_xor, descr_I_II),
jit_intrinsic(jit_long_xor, descr_l_ll),
jit_intrinsic(jit_ulong_xor, descr_L_LL),
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic
};
return apply_arith(func, &xor_descr, value1, value2, 1, 0, 0);
}
jit_value_t
jit_insn_not(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const not_descr = {
JIT_OP_INOT,
JIT_OP_INOT,
JIT_OP_LNOT,
JIT_OP_LNOT,
0, 0, 0,
jit_intrinsic(jit_int_not, descr_i_i),
jit_intrinsic(jit_uint_not, descr_I_I),
jit_intrinsic(jit_long_not, descr_l_l),
jit_intrinsic(jit_ulong_not, descr_L_L),
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic
};
return apply_unary_arith(func, ¬_descr, value, 1, 0, 0);
}
jit_value_t
jit_insn_shl(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const shl_descr = {
JIT_OP_ISHL,
JIT_OP_ISHL,
JIT_OP_LSHL,
JIT_OP_LSHL,
0, 0, 0,
jit_intrinsic(jit_int_shl, descr_i_iI),
jit_intrinsic(jit_uint_shl, descr_I_II),
jit_intrinsic(jit_long_shl, descr_l_lI),
jit_intrinsic(jit_ulong_shl, descr_L_LI),
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic
};
return apply_shift(func, &shl_descr, value1, value2);
}
jit_value_t
jit_insn_shr(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const shr_descr = {
JIT_OP_ISHR,
JIT_OP_ISHR_UN,
JIT_OP_LSHR,
JIT_OP_LSHR_UN,
0, 0, 0,
jit_intrinsic(jit_int_shr, descr_i_iI),
jit_intrinsic(jit_uint_shr, descr_I_II),
jit_intrinsic(jit_long_shr, descr_l_lI),
jit_intrinsic(jit_ulong_shr, descr_L_LI),
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic
};
return apply_shift(func, &shr_descr, value1, value2);
}
jit_value_t
jit_insn_ushr(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const ushr_descr = {
JIT_OP_ISHR_UN,
JIT_OP_ISHR_UN,
JIT_OP_LSHR_UN,
JIT_OP_LSHR_UN,
0, 0, 0,
jit_intrinsic(jit_uint_shr, descr_I_II),
jit_intrinsic(jit_uint_shr, descr_I_II),
jit_intrinsic(jit_ulong_shr, descr_L_LI),
jit_intrinsic(jit_ulong_shr, descr_L_LI),
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic
};
return apply_shift(func, &ushr_descr, value1, value2);
}
jit_value_t
jit_insn_sshr(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const sshr_descr = {
JIT_OP_ISHR,
JIT_OP_ISHR,
JIT_OP_LSHR,
JIT_OP_LSHR,
0, 0, 0,
jit_intrinsic(jit_int_shr, descr_i_iI),
jit_intrinsic(jit_int_shr, descr_i_iI),
jit_intrinsic(jit_long_shr, descr_l_lI),
jit_intrinsic(jit_long_shr, descr_l_lI),
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic
};
return apply_shift(func, &sshr_descr, value1, value2);
}
jit_value_t
jit_insn_eq(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const eq_descr = {
JIT_OP_IEQ,
JIT_OP_IEQ,
JIT_OP_LEQ,
JIT_OP_LEQ,
JIT_OP_FEQ,
JIT_OP_DEQ,
JIT_OP_NFEQ,
jit_intrinsic(jit_int_eq, descr_i_ii),
jit_intrinsic(jit_uint_eq, descr_i_II),
jit_intrinsic(jit_long_eq, descr_i_ll),
jit_intrinsic(jit_ulong_eq, descr_i_LL),
jit_intrinsic(jit_float32_eq, descr_i_ff),
jit_intrinsic(jit_float64_eq, descr_i_dd),
jit_intrinsic(jit_nfloat_eq, descr_i_DD)
};
return apply_compare(func, &eq_descr, value1, value2, 0);
}
jit_value_t
jit_insn_ne(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const ne_descr = {
JIT_OP_INE,
JIT_OP_INE,
JIT_OP_LNE,
JIT_OP_LNE,
JIT_OP_FNE,
JIT_OP_DNE,
JIT_OP_NFNE,
jit_intrinsic(jit_int_ne, descr_i_ii),
jit_intrinsic(jit_uint_ne, descr_i_II),
jit_intrinsic(jit_long_ne, descr_i_ll),
jit_intrinsic(jit_ulong_ne, descr_i_LL),
jit_intrinsic(jit_float32_ne, descr_i_ff),
jit_intrinsic(jit_float64_ne, descr_i_dd),
jit_intrinsic(jit_nfloat_ne, descr_i_DD)
};
return apply_compare(func, &ne_descr, value1, value2, 0);
}
jit_value_t
jit_insn_lt(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const lt_descr = {
JIT_OP_ILT,
JIT_OP_ILT_UN,
JIT_OP_LLT,
JIT_OP_LLT_UN,
JIT_OP_FLT,
JIT_OP_DLT,
JIT_OP_NFLT,
jit_intrinsic(jit_int_lt, descr_i_ii),
jit_intrinsic(jit_uint_lt, descr_i_II),
jit_intrinsic(jit_long_lt, descr_i_ll),
jit_intrinsic(jit_ulong_lt, descr_i_LL),
jit_intrinsic(jit_float32_lt, descr_i_ff),
jit_intrinsic(jit_float64_lt, descr_i_dd),
jit_intrinsic(jit_nfloat_lt, descr_i_DD)
};
return apply_compare(func, <_descr, value1, value2, 0);
}
jit_value_t
jit_insn_le(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const le_descr = {
JIT_OP_ILE,
JIT_OP_ILE_UN,
JIT_OP_LLE,
JIT_OP_LLE_UN,
JIT_OP_FLE,
JIT_OP_DLE,
JIT_OP_NFLE,
jit_intrinsic(jit_int_le, descr_i_ii),
jit_intrinsic(jit_uint_le, descr_i_II),
jit_intrinsic(jit_long_le, descr_i_ll),
jit_intrinsic(jit_ulong_le, descr_i_LL),
jit_intrinsic(jit_float32_le, descr_i_ff),
jit_intrinsic(jit_float64_le, descr_i_dd),
jit_intrinsic(jit_nfloat_le, descr_i_DD)
};
return apply_compare(func, &le_descr, value1, value2, 0);
}
jit_value_t
jit_insn_gt(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const gt_descr = {
JIT_OP_IGT,
JIT_OP_IGT_UN,
JIT_OP_LGT,
JIT_OP_LGT_UN,
JIT_OP_FGT,
JIT_OP_DGT,
JIT_OP_NFGT,
jit_intrinsic(jit_int_gt, descr_i_ii),
jit_intrinsic(jit_uint_gt, descr_i_II),
jit_intrinsic(jit_long_gt, descr_i_ll),
jit_intrinsic(jit_ulong_gt, descr_i_LL),
jit_intrinsic(jit_float32_gt, descr_i_ff),
jit_intrinsic(jit_float64_gt, descr_i_dd),
jit_intrinsic(jit_nfloat_gt, descr_i_DD)
};
return apply_compare(func, >_descr, value1, value2, 0);
}
jit_value_t
jit_insn_ge(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const ge_descr = {
JIT_OP_IGE,
JIT_OP_IGE_UN,
JIT_OP_LGE,
JIT_OP_LGE_UN,
JIT_OP_FGE,
JIT_OP_DGE,
JIT_OP_NFGE,
jit_intrinsic(jit_int_ge, descr_i_ii),
jit_intrinsic(jit_uint_ge, descr_i_II),
jit_intrinsic(jit_long_ge, descr_i_ll),
jit_intrinsic(jit_ulong_ge, descr_i_LL),
jit_intrinsic(jit_float32_ge, descr_i_ff),
jit_intrinsic(jit_float64_ge, descr_i_dd),
jit_intrinsic(jit_nfloat_ge, descr_i_DD)
};
return apply_compare(func, &ge_descr, value1, value2, 0);
}
jit_value_t
jit_insn_cmpl(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const cmpl_descr = {
JIT_OP_ICMP,
JIT_OP_ICMP_UN,
JIT_OP_LCMP,
JIT_OP_LCMP_UN,
JIT_OP_FCMPL,
JIT_OP_DCMPL,
JIT_OP_NFCMPL,
jit_intrinsic(jit_int_cmp, descr_i_ii),
jit_intrinsic(jit_uint_cmp, descr_i_II),
jit_intrinsic(jit_long_cmp, descr_i_ll),
jit_intrinsic(jit_ulong_cmp, descr_i_LL),
jit_intrinsic(jit_float32_cmpl, descr_i_ff),
jit_intrinsic(jit_float64_cmpl, descr_i_dd),
jit_intrinsic(jit_nfloat_cmpl, descr_i_DD)
};
return apply_compare(func, &cmpl_descr, value1, value2, 0);
}
jit_value_t
jit_insn_cmpg(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const cmpg_descr = {
JIT_OP_ICMP,
JIT_OP_ICMP_UN,
JIT_OP_LCMP,
JIT_OP_LCMP_UN,
JIT_OP_FCMPG,
JIT_OP_DCMPG,
JIT_OP_NFCMPG,
jit_intrinsic(jit_int_cmp, descr_i_ii),
jit_intrinsic(jit_uint_cmp, descr_i_II),
jit_intrinsic(jit_long_cmp, descr_i_ll),
jit_intrinsic(jit_ulong_cmp, descr_i_LL),
jit_intrinsic(jit_float32_cmpg, descr_i_ff),
jit_intrinsic(jit_float64_cmpg, descr_i_dd),
jit_intrinsic(jit_nfloat_cmpg, descr_i_DD)
};
return apply_compare(func, &cmpg_descr, value1, value2, 0);
}
jit_value_t
jit_insn_to_bool(jit_function_t func, jit_value_t value)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
int opcode;
jit_block_t block = func->builder->current_block;
jit_insn_t last = _jit_block_get_last(block);
if(value->is_temporary && last && last->dest == value)
{
opcode = last->opcode;
if(opcode >= JIT_OP_IEQ && opcode <= JIT_OP_NFGE_INV)
{
return value;
}
}
jit_type_t type = jit_type_promote_int(jit_type_normalize(value->type));
jit_value_t zero;
switch(type->kind)
{
default:
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
zero = jit_value_create_nint_constant(func, jit_type_int, 0);
break;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
zero = jit_value_create_long_constant(func, jit_type_long, 0);
break;
case JIT_TYPE_FLOAT32:
zero = jit_value_create_float32_constant(func, jit_type_float32,
(jit_float32) 0.0);
break;
case JIT_TYPE_FLOAT64:
zero = jit_value_create_float64_constant(func, jit_type_float64,
(jit_float64) 0.0);
break;
case JIT_TYPE_NFLOAT:
zero = jit_value_create_nfloat_constant(func, jit_type_nfloat,
(jit_nfloat) 0.0);
break;
}
if(!zero)
{
return 0;
}
return jit_insn_ne(func, value, zero);
}
jit_value_t
jit_insn_to_not_bool(jit_function_t func, jit_value_t value)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
int opcode;
jit_block_t block = func->builder->current_block;
jit_insn_t last = _jit_block_get_last(block);
if(value->is_temporary && last && last->dest == value)
{
opcode = last->opcode;
if(opcode >= JIT_OP_IEQ && opcode <= JIT_OP_NFGE_INV)
{
switch(opcode)
{
case JIT_OP_IEQ: opcode = JIT_OP_INE; break;
case JIT_OP_INE: opcode = JIT_OP_IEQ; break;
case JIT_OP_ILT: opcode = JIT_OP_IGE; break;
case JIT_OP_ILT_UN: opcode = JIT_OP_IGE_UN; break;
case JIT_OP_ILE: opcode = JIT_OP_IGT; break;
case JIT_OP_ILE_UN: opcode = JIT_OP_IGT_UN; break;
case JIT_OP_IGT: opcode = JIT_OP_ILE; break;
case JIT_OP_IGT_UN: opcode = JIT_OP_ILE_UN; break;
case JIT_OP_IGE: opcode = JIT_OP_ILT; break;
case JIT_OP_IGE_UN: opcode = JIT_OP_ILT_UN; break;
case JIT_OP_LEQ: opcode = JIT_OP_LNE; break;
case JIT_OP_LNE: opcode = JIT_OP_LEQ; break;
case JIT_OP_LLT: opcode = JIT_OP_LGE; break;
case JIT_OP_LLT_UN: opcode = JIT_OP_LGE_UN; break;
case JIT_OP_LLE: opcode = JIT_OP_LGT; break;
case JIT_OP_LLE_UN: opcode = JIT_OP_LGT_UN; break;
case JIT_OP_LGT: opcode = JIT_OP_LLE; break;
case JIT_OP_LGT_UN: opcode = JIT_OP_LLE_UN; break;
case JIT_OP_LGE: opcode = JIT_OP_LLT; break;
case JIT_OP_LGE_UN: opcode = JIT_OP_LLT_UN; break;
case JIT_OP_FEQ: opcode = JIT_OP_FNE; break;
case JIT_OP_FNE: opcode = JIT_OP_FEQ; break;
case JIT_OP_FLT: opcode = JIT_OP_FGE_INV; break;
case JIT_OP_FLE: opcode = JIT_OP_FGT_INV; break;
case JIT_OP_FGT: opcode = JIT_OP_FLE_INV; break;
case JIT_OP_FGE: opcode = JIT_OP_FLT_INV; break;
case JIT_OP_FLT_INV: opcode = JIT_OP_FGE; break;
case JIT_OP_FLE_INV: opcode = JIT_OP_FGT; break;
case JIT_OP_FGT_INV: opcode = JIT_OP_FLE; break;
case JIT_OP_FGE_INV: opcode = JIT_OP_FLT; break;
case JIT_OP_DEQ: opcode = JIT_OP_DNE; break;
case JIT_OP_DNE: opcode = JIT_OP_DEQ; break;
case JIT_OP_DLT: opcode = JIT_OP_DGE_INV; break;
case JIT_OP_DLE: opcode = JIT_OP_DGT_INV; break;
case JIT_OP_DGT: opcode = JIT_OP_DLE_INV; break;
case JIT_OP_DGE: opcode = JIT_OP_DLT_INV; break;
case JIT_OP_DLT_INV: opcode = JIT_OP_DGE; break;
case JIT_OP_DLE_INV: opcode = JIT_OP_DGT; break;
case JIT_OP_DGT_INV: opcode = JIT_OP_DLE; break;
case JIT_OP_DGE_INV: opcode = JIT_OP_DLT; break;
case JIT_OP_NFEQ: opcode = JIT_OP_NFNE; break;
case JIT_OP_NFNE: opcode = JIT_OP_NFEQ; break;
case JIT_OP_NFLT: opcode = JIT_OP_NFGE_INV; break;
case JIT_OP_NFLE: opcode = JIT_OP_NFGT_INV; break;
case JIT_OP_NFGT: opcode = JIT_OP_NFLE_INV; break;
case JIT_OP_NFGE: opcode = JIT_OP_NFLT_INV; break;
case JIT_OP_NFLT_INV: opcode = JIT_OP_NFGE; break;
case JIT_OP_NFLE_INV: opcode = JIT_OP_NFGT; break;
case JIT_OP_NFGT_INV: opcode = JIT_OP_NFLE; break;
case JIT_OP_NFGE_INV: opcode = JIT_OP_NFLT; break;
}
last->opcode = (short) opcode;
return value;
}
}
jit_type_t type = jit_type_promote_int(jit_type_normalize(value->type));
jit_value_t zero;
switch(type->kind)
{
default:
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
zero = jit_value_create_nint_constant(func, jit_type_int, 0);
break;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
zero = jit_value_create_long_constant(func, jit_type_long, 0);
break;
case JIT_TYPE_FLOAT32:
zero = jit_value_create_float32_constant(func, jit_type_float32,
(jit_float32) 0.0);
break;
case JIT_TYPE_FLOAT64:
zero = jit_value_create_float64_constant(func, jit_type_float64,
(jit_float64) 0.0);
break;
case JIT_TYPE_NFLOAT:
zero = jit_value_create_nfloat_constant(func, jit_type_nfloat,
(jit_nfloat) 0.0);
break;
}
if(!zero)
{
return 0;
}
return jit_insn_eq(func, value, zero);
}
jit_value_t
jit_insn_acos(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const acos_descr = {
0, 0, 0, 0,
JIT_OP_FACOS,
JIT_OP_DACOS,
JIT_OP_NFACOS,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_acos, descr_f_f),
jit_intrinsic(jit_float64_acos, descr_d_d),
jit_intrinsic(jit_nfloat_acos, descr_D_D)
};
return apply_unary_arith(func, &acos_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_asin(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const asin_descr = {
0, 0, 0, 0,
JIT_OP_FASIN,
JIT_OP_DASIN,
JIT_OP_NFASIN,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_asin, descr_f_f),
jit_intrinsic(jit_float64_asin, descr_d_d),
jit_intrinsic(jit_nfloat_asin, descr_D_D)
};
return apply_unary_arith(func, &asin_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_atan(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const atan_descr = {
0, 0, 0, 0,
JIT_OP_FATAN,
JIT_OP_DATAN,
JIT_OP_NFATAN,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_atan, descr_f_f),
jit_intrinsic(jit_float64_atan, descr_d_d),
jit_intrinsic(jit_nfloat_atan, descr_D_D)
};
return apply_unary_arith(func, &atan_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_atan2(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const atan2_descr = {
0, 0, 0, 0,
JIT_OP_FATAN2,
JIT_OP_DATAN2,
JIT_OP_NFATAN2,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_atan2, descr_f_ff),
jit_intrinsic(jit_float64_atan2, descr_d_dd),
jit_intrinsic(jit_nfloat_atan2, descr_D_DD)
};
return apply_arith(func, &atan2_descr, value1, value2, 0, 1, 0);
}
jit_value_t
jit_insn_ceil(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const ceil_descr = {
0, 0, 0, 0,
JIT_OP_FCEIL,
JIT_OP_DCEIL,
JIT_OP_NFCEIL,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_ceil, descr_f_f),
jit_intrinsic(jit_float64_ceil, descr_d_d),
jit_intrinsic(jit_nfloat_ceil, descr_D_D)
};
return apply_unary_arith(func, &ceil_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_cos(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const cos_descr = {
0, 0, 0, 0,
JIT_OP_FCOS,
JIT_OP_DCOS,
JIT_OP_NFCOS,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_cos, descr_f_f),
jit_intrinsic(jit_float64_cos, descr_d_d),
jit_intrinsic(jit_nfloat_cos, descr_D_D)
};
return apply_unary_arith(func, &cos_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_cosh(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const cosh_descr = {
0, 0, 0, 0,
JIT_OP_FCOSH,
JIT_OP_DCOSH,
JIT_OP_NFCOSH,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_cosh, descr_f_f),
jit_intrinsic(jit_float64_cosh, descr_d_d),
jit_intrinsic(jit_nfloat_cosh, descr_D_D)
};
return apply_unary_arith(func, &cosh_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_exp(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const exp_descr = {
0, 0, 0, 0,
JIT_OP_FEXP,
JIT_OP_DEXP,
JIT_OP_NFEXP,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_exp, descr_f_f),
jit_intrinsic(jit_float64_exp, descr_d_d),
jit_intrinsic(jit_nfloat_exp, descr_D_D)
};
return apply_unary_arith(func, &exp_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_floor(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const floor_descr = {
0, 0, 0, 0,
JIT_OP_FFLOOR,
JIT_OP_DFLOOR,
JIT_OP_NFFLOOR,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_floor, descr_f_f),
jit_intrinsic(jit_float64_floor, descr_d_d),
jit_intrinsic(jit_nfloat_floor, descr_D_D)
};
return apply_unary_arith(func, &floor_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_log(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const log_descr = {
0, 0, 0, 0,
JIT_OP_FLOG,
JIT_OP_DLOG,
JIT_OP_NFLOG,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_log, descr_f_f),
jit_intrinsic(jit_float64_log, descr_d_d),
jit_intrinsic(jit_nfloat_log, descr_D_D)
};
return apply_unary_arith(func, &log_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_log10(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const log10_descr = {
0, 0, 0, 0,
JIT_OP_FLOG10,
JIT_OP_DLOG10,
JIT_OP_NFLOG10,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_log10, descr_f_f),
jit_intrinsic(jit_float64_log10, descr_d_d),
jit_intrinsic(jit_nfloat_log10, descr_D_D)
};
return apply_unary_arith(func, &log10_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_pow(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const pow_descr = {
0, 0, 0, 0,
JIT_OP_FPOW,
JIT_OP_DPOW,
JIT_OP_NFPOW,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_pow, descr_f_ff),
jit_intrinsic(jit_float64_pow, descr_d_dd),
jit_intrinsic(jit_nfloat_pow, descr_D_DD)
};
return apply_arith(func, &pow_descr, value1, value2, 0, 1, 0);
}
jit_value_t
jit_insn_rint(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const rint_descr = {
0, 0, 0, 0,
JIT_OP_FRINT,
JIT_OP_DRINT,
JIT_OP_NFRINT,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_rint, descr_f_f),
jit_intrinsic(jit_float64_rint, descr_d_d),
jit_intrinsic(jit_nfloat_rint, descr_D_D)
};
return apply_unary_arith(func, &rint_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_round(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const round_descr = {
0, 0, 0, 0,
JIT_OP_FROUND,
JIT_OP_DROUND,
JIT_OP_NFROUND,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_round, descr_f_f),
jit_intrinsic(jit_float64_round, descr_d_d),
jit_intrinsic(jit_nfloat_round, descr_D_D)
};
return apply_unary_arith(func, &round_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_sin(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const sin_descr = {
0, 0, 0, 0,
JIT_OP_FSIN,
JIT_OP_DSIN,
JIT_OP_NFSIN,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_sin, descr_f_f),
jit_intrinsic(jit_float64_sin, descr_d_d),
jit_intrinsic(jit_nfloat_sin, descr_D_D)
};
return apply_unary_arith(func, &sin_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_sinh(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const sinh_descr = {
0, 0, 0, 0,
JIT_OP_FSINH,
JIT_OP_DSINH,
JIT_OP_NFSINH,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_sinh, descr_f_f),
jit_intrinsic(jit_float64_sinh, descr_d_d),
jit_intrinsic(jit_nfloat_sinh, descr_D_D)
};
return apply_unary_arith(func, &sinh_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_sqrt(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const sqrt_descr = {
0, 0, 0, 0,
JIT_OP_FSQRT,
JIT_OP_DSQRT,
JIT_OP_NFSQRT,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_sqrt, descr_f_f),
jit_intrinsic(jit_float64_sqrt, descr_d_d),
jit_intrinsic(jit_nfloat_sqrt, descr_D_D)
};
return apply_unary_arith(func, &sqrt_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_tan(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const tan_descr = {
0, 0, 0, 0,
JIT_OP_FTAN,
JIT_OP_DTAN,
JIT_OP_NFTAN,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_tan, descr_f_f),
jit_intrinsic(jit_float64_tan, descr_d_d),
jit_intrinsic(jit_nfloat_tan, descr_D_D)
};
return apply_unary_arith(func, &tan_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_tanh(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const tanh_descr = {
0, 0, 0, 0,
JIT_OP_FTANH,
JIT_OP_DTANH,
JIT_OP_NFTANH,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_tanh, descr_f_f),
jit_intrinsic(jit_float64_tanh, descr_d_d),
jit_intrinsic(jit_nfloat_tanh, descr_D_D)
};
return apply_unary_arith(func, &tanh_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_trunc(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const trunc_descr = {
0, 0, 0, 0,
JIT_OP_FTRUNC,
JIT_OP_DTRUNC,
JIT_OP_NFTRUNC,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_trunc, descr_f_f),
jit_intrinsic(jit_float64_trunc, descr_d_d),
jit_intrinsic(jit_nfloat_trunc, descr_D_D)
};
return apply_unary_arith(func, &trunc_descr, value, 0, 1, 0);
}
jit_value_t
jit_insn_is_nan(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const is_nan_descr = {
0, 0, 0, 0,
JIT_OP_IS_FNAN,
JIT_OP_IS_DNAN,
JIT_OP_IS_NFNAN,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_is_nan, descr_i_f),
jit_intrinsic(jit_float64_is_nan, descr_i_d),
jit_intrinsic(jit_nfloat_is_nan, descr_i_D)
};
return test_float_value(func, &is_nan_descr, value);
}
jit_value_t
jit_insn_is_finite(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const is_finite_descr = {
0, 0, 0, 0,
JIT_OP_IS_FFINITE,
JIT_OP_IS_DFINITE,
JIT_OP_IS_NFFINITE,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_is_finite, descr_i_f),
jit_intrinsic(jit_float64_is_finite, descr_i_d),
jit_intrinsic(jit_nfloat_is_finite, descr_i_D)
};
return test_float_value(func, &is_finite_descr, value);
}
jit_value_t
jit_insn_is_inf(jit_function_t func, jit_value_t value)
{
static jit_opcode_descr const is_inf_descr = {
0, 0, 0, 0,
JIT_OP_IS_FINF,
JIT_OP_IS_DINF,
JIT_OP_IS_NFINF,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_no_intrinsic,
jit_intrinsic(jit_float32_is_inf, descr_i_f),
jit_intrinsic(jit_float64_is_inf, descr_i_d),
jit_intrinsic(jit_nfloat_is_inf, descr_i_D)
};
return test_float_value(func, &is_inf_descr, value);
}
jit_value_t
jit_insn_abs(jit_function_t func, jit_value_t value)
{
int oper;
void *intrinsic;
const char *name;
const jit_intrinsic_descr_t *descr;
jit_type_t type = jit_type_promote_int(jit_type_normalize(value->type));
switch (type->kind)
{
case JIT_TYPE_INT:
oper = JIT_OP_IABS;
intrinsic = (void *) jit_int_abs;
name = "jit_int_abs";
descr = &descr_i_i;
break;
case JIT_TYPE_UINT:
oper = 0;
intrinsic = (void *) 0;
name = 0;
descr = 0;
break;
case JIT_TYPE_LONG:
oper = JIT_OP_LABS;
intrinsic = (void *) jit_long_abs;
name = "jit_long_abs";
descr = &descr_l_l;
break;
case JIT_TYPE_ULONG:
oper = 0;
intrinsic = (void *) 0;
name = 0;
descr = 0;
break;
case JIT_TYPE_FLOAT32:
oper = JIT_OP_FABS;
intrinsic = (void *) jit_float32_abs;
name = "jit_float32_abs";
descr = &descr_f_f;
break;
case JIT_TYPE_FLOAT64:
oper = JIT_OP_DABS;
intrinsic = (void *) jit_float64_abs;
name = "jit_float64_abs";
descr = &descr_d_d;
break;
case JIT_TYPE_NFLOAT:
oper = JIT_OP_NFABS;
intrinsic = (void *) jit_nfloat_abs;
name = "jit_nfloat_abs";
descr = &descr_D_D;
break;
default:
return 0;
}
value = jit_insn_convert(func, value, type, 0);
if(!value)
{
return 0;
}
if(!oper)
{
return value;
}
if(jit_value_is_constant(value))
{
jit_value_t result = _jit_opcode_apply_unary(func, oper, value, type);
if(result)
{
return result;
}
}
if(!_jit_opcode_is_supported(oper))
{
return jit_insn_call_intrinsic(func, name, intrinsic, descr, value, 0);
}
return apply_unary(func, oper, value, type);
}
jit_value_t
jit_insn_min(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const min_descr = {
JIT_OP_IMIN,
JIT_OP_IMIN_UN,
JIT_OP_LMIN,
JIT_OP_LMIN_UN,
JIT_OP_FMIN,
JIT_OP_DMIN,
JIT_OP_NFMIN,
jit_intrinsic(jit_int_min, descr_i_ii),
jit_intrinsic(jit_uint_min, descr_I_II),
jit_intrinsic(jit_long_min, descr_l_ll),
jit_intrinsic(jit_ulong_min, descr_L_LL),
jit_intrinsic(jit_float32_min, descr_f_ff),
jit_intrinsic(jit_float64_min, descr_d_dd),
jit_intrinsic(jit_nfloat_min, descr_D_DD)
};
return apply_arith(func, &min_descr, value1, value2, 0, 0, 0);
}
jit_value_t
jit_insn_max(jit_function_t func, jit_value_t value1, jit_value_t value2)
{
static jit_opcode_descr const max_descr = {
JIT_OP_IMAX,
JIT_OP_IMAX_UN,
JIT_OP_LMAX,
JIT_OP_LMAX_UN,
JIT_OP_FMAX,
JIT_OP_DMAX,
JIT_OP_NFMAX,
jit_intrinsic(jit_int_max, descr_i_ii),
jit_intrinsic(jit_uint_max, descr_I_II),
jit_intrinsic(jit_long_max, descr_l_ll),
jit_intrinsic(jit_ulong_max, descr_L_LL),
jit_intrinsic(jit_float32_max, descr_f_ff),
jit_intrinsic(jit_float64_max, descr_d_dd),
jit_intrinsic(jit_nfloat_max, descr_D_DD)
};
return apply_arith(func, &max_descr, value1, value2, 0, 0, 0);
}
jit_value_t
jit_insn_sign(jit_function_t func, jit_value_t value)
{
int oper;
void *intrinsic;
const char *name;
const jit_intrinsic_descr_t *descr;
jit_value_t zero;
jit_type_t type = jit_type_promote_int(jit_type_normalize(value->type));
switch (type->kind)
{
case JIT_TYPE_INT:
oper = JIT_OP_ISIGN;
intrinsic = (void *) jit_int_sign;
name = "jit_int_sign";
descr = &descr_i_i;
break;
case JIT_TYPE_UINT:
zero = jit_value_create_nint_constant(func, jit_type_uint, 0);
if(!zero)
{
return 0;
}
return jit_insn_ne(func, value, zero);
case JIT_TYPE_LONG:
oper = JIT_OP_LSIGN;
intrinsic = (void *) jit_long_sign;
name = "jit_long_sign";
descr = &descr_i_l;
break;
case JIT_TYPE_ULONG:
zero = jit_value_create_long_constant(func, jit_type_ulong, 0);
if(!zero)
{
return 0;
}
return jit_insn_ne(func, value, zero);
case JIT_TYPE_FLOAT32:
oper = JIT_OP_FSIGN;
intrinsic = (void *) jit_float32_sign;
name = "jit_float32_sign";
descr = &descr_i_f;
break;
case JIT_TYPE_FLOAT64:
oper = JIT_OP_DSIGN;
intrinsic = (void *) jit_float64_sign;
name = "jit_float64_sign";
descr = &descr_i_d;
break;
case JIT_TYPE_NFLOAT:
oper = JIT_OP_NFSIGN;
intrinsic = (void *) jit_nfloat_sign;
name = "jit_nfloat_sign";
descr = &descr_i_D;
break;
default:
return 0;
}
value = jit_insn_convert(func, value, type, 0);
if(!value)
{
return 0;
}
if(jit_value_is_constant(value))
{
jit_value_t result = _jit_opcode_apply_unary(func, oper, value, type);
if(result)
{
return result;
}
}
if(!_jit_opcode_is_supported(oper))
{
return jit_insn_call_intrinsic(func, name, intrinsic, descr, value, 0);
}
return apply_unary(func, oper, value, jit_type_int);
}
int
jit_insn_branch(jit_function_t func, jit_label_t *label)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
if(*label == jit_label_undefined)
{
*label = func->builder->next_label++;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) JIT_OP_BR;
insn->flags = JIT_INSN_DEST_IS_LABEL;
insn->dest = (jit_value_t) *label;
func->builder->current_block->ends_in_dead = 1;
return jit_insn_new_block(func);
}
int
jit_insn_branch_if(jit_function_t func, jit_value_t value, jit_label_t *label)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
if(*label == jit_label_undefined)
{
*label = func->builder->next_label++;
}
if(jit_value_is_constant(value))
{
if(jit_value_is_true(value))
{
return jit_insn_branch(func, label);
}
else
{
return 1;
}
}
int opcode;
jit_value_t value1;
jit_value_t value2;
jit_block_t block = func->builder->current_block;
jit_insn_t prev = _jit_block_get_last(block);
if(value->is_temporary && prev && prev->dest == value)
{
opcode = prev->opcode;
if(opcode >= JIT_OP_IEQ && opcode <= JIT_OP_NFGE_INV)
{
switch(opcode)
{
case JIT_OP_IEQ: opcode = JIT_OP_BR_IEQ; break;
case JIT_OP_INE: opcode = JIT_OP_BR_INE; break;
case JIT_OP_ILT: opcode = JIT_OP_BR_ILT; break;
case JIT_OP_ILT_UN: opcode = JIT_OP_BR_ILT_UN; break;
case JIT_OP_ILE: opcode = JIT_OP_BR_ILE; break;
case JIT_OP_ILE_UN: opcode = JIT_OP_BR_ILE_UN; break;
case JIT_OP_IGT: opcode = JIT_OP_BR_IGT; break;
case JIT_OP_IGT_UN: opcode = JIT_OP_BR_IGT_UN; break;
case JIT_OP_IGE: opcode = JIT_OP_BR_IGE; break;
case JIT_OP_IGE_UN: opcode = JIT_OP_BR_IGE_UN; break;
case JIT_OP_LEQ: opcode = JIT_OP_BR_LEQ; break;
case JIT_OP_LNE: opcode = JIT_OP_BR_LNE; break;
case JIT_OP_LLT: opcode = JIT_OP_BR_LLT; break;
case JIT_OP_LLT_UN: opcode = JIT_OP_BR_LLT_UN; break;
case JIT_OP_LLE: opcode = JIT_OP_BR_LLE; break;
case JIT_OP_LLE_UN: opcode = JIT_OP_BR_LLE_UN; break;
case JIT_OP_LGT: opcode = JIT_OP_BR_LGT; break;
case JIT_OP_LGT_UN: opcode = JIT_OP_BR_LGT_UN; break;
case JIT_OP_LGE: opcode = JIT_OP_BR_LGE; break;
case JIT_OP_LGE_UN: opcode = JIT_OP_BR_LGE_UN; break;
case JIT_OP_FEQ: opcode = JIT_OP_BR_FEQ; break;
case JIT_OP_FNE: opcode = JIT_OP_BR_FNE; break;
case JIT_OP_FLT: opcode = JIT_OP_BR_FLT; break;
case JIT_OP_FLE: opcode = JIT_OP_BR_FLE; break;
case JIT_OP_FGT: opcode = JIT_OP_BR_FGT; break;
case JIT_OP_FGE: opcode = JIT_OP_BR_FGE; break;
case JIT_OP_FLT_INV: opcode = JIT_OP_BR_FLT_INV; break;
case JIT_OP_FLE_INV: opcode = JIT_OP_BR_FLE_INV; break;
case JIT_OP_FGT_INV: opcode = JIT_OP_BR_FGT_INV; break;
case JIT_OP_FGE_INV: opcode = JIT_OP_BR_FGE_INV; break;
case JIT_OP_DEQ: opcode = JIT_OP_BR_DEQ; break;
case JIT_OP_DNE: opcode = JIT_OP_BR_DNE; break;
case JIT_OP_DLT: opcode = JIT_OP_BR_DLT; break;
case JIT_OP_DLE: opcode = JIT_OP_BR_DLE; break;
case JIT_OP_DGT: opcode = JIT_OP_BR_DGT; break;
case JIT_OP_DGE: opcode = JIT_OP_BR_DGE; break;
case JIT_OP_DLT_INV: opcode = JIT_OP_BR_DLT_INV; break;
case JIT_OP_DLE_INV: opcode = JIT_OP_BR_DLE_INV; break;
case JIT_OP_DGT_INV: opcode = JIT_OP_BR_DGT_INV; break;
case JIT_OP_DGE_INV: opcode = JIT_OP_BR_DGE_INV; break;
case JIT_OP_NFEQ: opcode = JIT_OP_BR_NFEQ; break;
case JIT_OP_NFNE: opcode = JIT_OP_BR_NFNE; break;
case JIT_OP_NFLT: opcode = JIT_OP_BR_NFLT; break;
case JIT_OP_NFLE: opcode = JIT_OP_BR_NFLE; break;
case JIT_OP_NFGT: opcode = JIT_OP_BR_NFGT; break;
case JIT_OP_NFGE: opcode = JIT_OP_BR_NFGE; break;
case JIT_OP_NFLT_INV: opcode = JIT_OP_BR_NFLT_INV; break;
case JIT_OP_NFLE_INV: opcode = JIT_OP_BR_NFLE_INV; break;
case JIT_OP_NFGT_INV: opcode = JIT_OP_BR_NFGT_INV; break;
case JIT_OP_NFGE_INV: opcode = JIT_OP_BR_NFGE_INV; break;
}
value1 = prev->value1;
value2 = prev->value2;
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) opcode;
insn->flags = JIT_INSN_DEST_IS_LABEL;
insn->dest = (jit_value_t) *label;
insn->value1 = value1;
jit_value_ref(func, value1);
insn->value2 = value2;
jit_value_ref(func, value2);
goto add_block;
}
}
jit_type_t type = jit_type_promote_int(jit_type_normalize(value->type));
value = jit_insn_convert(func, value, type, 0);
if(!value)
{
return 0;
}
switch(type->kind)
{
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
opcode = JIT_OP_BR_ITRUE;
value2 = 0;
break;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
opcode = JIT_OP_BR_LTRUE;
value2 = 0;
break;
case JIT_TYPE_FLOAT32:
opcode = JIT_OP_BR_FNE;
value2 = jit_value_create_float32_constant(func, jit_type_float32,
(jit_float32) 0.0);
if(!value2)
{
return 0;
}
break;
case JIT_TYPE_FLOAT64:
opcode = JIT_OP_BR_DNE;
value2 = jit_value_create_float64_constant(func, jit_type_float64,
(jit_float64) 0.0);
if(!value2)
{
return 0;
}
break;
case JIT_TYPE_NFLOAT:
type = jit_type_nfloat;
opcode = JIT_OP_BR_NFNE;
value2 = jit_value_create_nfloat_constant(func, jit_type_nfloat,
(jit_nfloat) 0.0);
if(!value2)
{
return 0;
}
break;
default:
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) opcode;
insn->flags = JIT_INSN_DEST_IS_LABEL;
insn->dest = (jit_value_t) *label;
insn->value1 = value;
jit_value_ref(func, value);
if(value2)
{
insn->value2 = value2;
jit_value_ref(func, value2);
}
add_block:
return jit_insn_new_block(func);
}
int
jit_insn_branch_if_not(jit_function_t func, jit_value_t value, jit_label_t *label)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
if(*label == jit_label_undefined)
{
*label = func->builder->next_label++;
}
if(jit_value_is_constant(value))
{
if(!jit_value_is_true(value))
{
return jit_insn_branch(func, label);
}
else
{
return 1;
}
}
int opcode;
jit_value_t value1;
jit_value_t value2;
jit_block_t block = func->builder->current_block;
jit_insn_t prev = _jit_block_get_last(block);
if(value->is_temporary && prev && prev->dest == value)
{
opcode = prev->opcode;
if(opcode >= JIT_OP_IEQ && opcode <= JIT_OP_NFGE_INV)
{
switch(opcode)
{
case JIT_OP_IEQ: opcode = JIT_OP_BR_INE; break;
case JIT_OP_INE: opcode = JIT_OP_BR_IEQ; break;
case JIT_OP_ILT: opcode = JIT_OP_BR_IGE; break;
case JIT_OP_ILT_UN: opcode = JIT_OP_BR_IGE_UN; break;
case JIT_OP_ILE: opcode = JIT_OP_BR_IGT; break;
case JIT_OP_ILE_UN: opcode = JIT_OP_BR_IGT_UN; break;
case JIT_OP_IGT: opcode = JIT_OP_BR_ILE; break;
case JIT_OP_IGT_UN: opcode = JIT_OP_BR_ILE_UN; break;
case JIT_OP_IGE: opcode = JIT_OP_BR_ILT; break;
case JIT_OP_IGE_UN: opcode = JIT_OP_BR_ILT_UN; break;
case JIT_OP_LEQ: opcode = JIT_OP_BR_LNE; break;
case JIT_OP_LNE: opcode = JIT_OP_BR_LEQ; break;
case JIT_OP_LLT: opcode = JIT_OP_BR_LGE; break;
case JIT_OP_LLT_UN: opcode = JIT_OP_BR_LGE_UN; break;
case JIT_OP_LLE: opcode = JIT_OP_BR_LGT; break;
case JIT_OP_LLE_UN: opcode = JIT_OP_BR_LGT_UN; break;
case JIT_OP_LGT: opcode = JIT_OP_BR_LLE; break;
case JIT_OP_LGT_UN: opcode = JIT_OP_BR_LLE_UN; break;
case JIT_OP_LGE: opcode = JIT_OP_BR_LLT; break;
case JIT_OP_LGE_UN: opcode = JIT_OP_BR_LLT_UN; break;
case JIT_OP_FEQ: opcode = JIT_OP_BR_FNE; break;
case JIT_OP_FNE: opcode = JIT_OP_BR_FEQ; break;
case JIT_OP_FLT: opcode = JIT_OP_BR_FGE_INV; break;
case JIT_OP_FLE: opcode = JIT_OP_BR_FGT_INV; break;
case JIT_OP_FGT: opcode = JIT_OP_BR_FLE_INV; break;
case JIT_OP_FGE: opcode = JIT_OP_BR_FLT_INV; break;
case JIT_OP_FLT_INV: opcode = JIT_OP_BR_FGE; break;
case JIT_OP_FLE_INV: opcode = JIT_OP_BR_FGT; break;
case JIT_OP_FGT_INV: opcode = JIT_OP_BR_FLE; break;
case JIT_OP_FGE_INV: opcode = JIT_OP_BR_FLT; break;
case JIT_OP_DEQ: opcode = JIT_OP_BR_DNE; break;
case JIT_OP_DNE: opcode = JIT_OP_BR_DEQ; break;
case JIT_OP_DLT: opcode = JIT_OP_BR_DGE_INV; break;
case JIT_OP_DLE: opcode = JIT_OP_BR_DGT_INV; break;
case JIT_OP_DGT: opcode = JIT_OP_BR_DLE_INV; break;
case JIT_OP_DGE: opcode = JIT_OP_BR_DLT_INV; break;
case JIT_OP_DLT_INV: opcode = JIT_OP_BR_DGE; break;
case JIT_OP_DLE_INV: opcode = JIT_OP_BR_DGT; break;
case JIT_OP_DGT_INV: opcode = JIT_OP_BR_DLE; break;
case JIT_OP_DGE_INV: opcode = JIT_OP_BR_DLT; break;
case JIT_OP_NFEQ: opcode = JIT_OP_BR_NFNE; break;
case JIT_OP_NFNE: opcode = JIT_OP_BR_NFEQ; break;
case JIT_OP_NFLT: opcode = JIT_OP_BR_NFGE_INV; break;
case JIT_OP_NFLE: opcode = JIT_OP_BR_NFGT_INV; break;
case JIT_OP_NFGT: opcode = JIT_OP_BR_NFLE_INV; break;
case JIT_OP_NFGE: opcode = JIT_OP_BR_NFLT_INV; break;
case JIT_OP_NFLT_INV: opcode = JIT_OP_BR_NFGE; break;
case JIT_OP_NFLE_INV: opcode = JIT_OP_BR_NFGT; break;
case JIT_OP_NFGT_INV: opcode = JIT_OP_BR_NFLE; break;
case JIT_OP_NFGE_INV: opcode = JIT_OP_BR_NFLT; break;
}
value1 = prev->value1;
value2 = prev->value2;
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) opcode;
insn->flags = JIT_INSN_DEST_IS_LABEL;
insn->dest = (jit_value_t) *label;
insn->value1 = value1;
jit_value_ref(func, value1);
insn->value2 = value2;
jit_value_ref(func, value2);
goto add_block;
}
}
jit_type_t type = jit_type_promote_int(jit_type_normalize(value->type));
value = jit_insn_convert(func, value, type, 0);
if(!value)
{
return 0;
}
switch(type->kind)
{
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
opcode = JIT_OP_BR_IFALSE;
value2 = 0;
break;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
opcode = JIT_OP_BR_LFALSE;
value2 = 0;
break;
case JIT_TYPE_FLOAT32:
opcode = JIT_OP_BR_FEQ;
value2 = jit_value_create_float32_constant(func, jit_type_float32,
(jit_float32) 0.0);
if(!value2)
{
return 0;
}
break;
case JIT_TYPE_FLOAT64:
opcode = JIT_OP_BR_DEQ;
value2 = jit_value_create_float64_constant(func, jit_type_float64,
(jit_float64) 0.0);
if(!value2)
{
return 0;
}
break;
case JIT_TYPE_NFLOAT:
opcode = JIT_OP_BR_NFEQ;
value2 = jit_value_create_nfloat_constant(func, jit_type_nfloat,
(jit_nfloat) 0.0);
if(!value2)
{
return 0;
}
break;
default:
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) opcode;
insn->flags = JIT_INSN_DEST_IS_LABEL;
insn->dest = (jit_value_t) *label;
insn->value1 = value;
jit_value_ref(func, value);
if(value2)
{
insn->value2 = value2;
jit_value_ref(func, value2);
}
add_block:
return jit_insn_new_block(func);
}
int
jit_insn_jump_table(jit_function_t func, jit_value_t value,
jit_label_t *labels, unsigned int num_labels)
{
if(!num_labels)
{
return 0;
}
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
unsigned int index;
for(index = 0; index < num_labels; index++)
{
if(labels[index] == jit_label_undefined)
{
labels[index] = func->builder->next_label++;
}
}
if(jit_value_is_constant(value))
{
index = jit_value_get_nint_constant(value);
if(index < num_labels && index >= 0)
{
return jit_insn_branch(func, &labels[index]);
}
else
{
return 1;
}
}
jit_label_t *new_labels = jit_malloc(num_labels * sizeof(jit_label_t));
if(!new_labels)
{
return 0;
}
for(index = 0; index < num_labels; index++)
{
new_labels[index] = labels[index];
}
jit_value_t value_labels =
jit_value_create_nint_constant(func, jit_type_void_ptr, (jit_nint) new_labels);
if(!value_labels)
{
jit_free(new_labels);
return 0;
}
value_labels->free_address = 1;
jit_value_t value_num_labels =
jit_value_create_nint_constant(func, jit_type_uint, num_labels);
if(!value_num_labels)
{
_jit_value_free(value_labels);
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = JIT_OP_JUMP_TABLE;
insn->flags = JIT_INSN_DEST_IS_VALUE;
insn->dest = value;
jit_value_ref(func, value);
insn->value1 = value_labels;
insn->value2 = value_num_labels;
return jit_insn_new_block(func);
}
jit_value_t
jit_insn_address_of(jit_function_t func, jit_value_t value)
{
if(jit_value_is_constant(value))
{
return 0;
}
jit_type_t type = jit_type_create_pointer(jit_value_get_type(value), 1);
if(!type)
{
return 0;
}
jit_value_set_addressable(value);
jit_value_t result = apply_unary(func, JIT_OP_ADDRESS_OF, value, type);
jit_type_free(type);
return result;
}
jit_value_t
jit_insn_address_of_label(jit_function_t func, jit_label_t *label)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(*label == jit_label_undefined)
{
*label = func->builder->next_label++;
}
if(!_jit_block_record_label_flags(func, *label, JIT_LABEL_ADDRESS_OF))
{
return 0;
}
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
jit_value_t dest = jit_value_create(func, jit_type_void_ptr);
if(!dest)
{
return 0;
}
insn->opcode = (short) JIT_OP_ADDRESS_OF_LABEL;
insn->flags = JIT_INSN_VALUE1_IS_LABEL;
insn->dest = dest;
insn->value1 = (jit_value_t) *label;
return dest;
}
typedef struct jit_convert_info
{
int cvt1;
jit_type_t type1;
int cvt2;
jit_type_t type2;
int cvt3;
jit_type_t type3;
} jit_convert_info_t;
#define CVT(opcode,name) opcode, (jit_type_t) &_jit_type_##name##_def
#define CVT_NONE 0, 0
typedef struct jit_convert_intrinsic
{
const char *name;
void *func;
jit_intrinsic_descr_t descr;
} jit_convert_intrinsic_t;
#define CVT_INTRINSIC_NULL \
{0, 0, {0, 0, 0, 0}}
#define CVT_INTRINSIC(name, intype, outtype) \
{ #name, (void *) name, \
{ (jit_type_t) &_jit_type_##outtype##_def, 0, \
(jit_type_t) &_jit_type_##intype##_def, 0 } }
#define CVT_INTRINSIC_CHECK(name, intype, outtype) \
{ #name, (void *) name, \
{ (jit_type_t) &_jit_type_int_def, \
(jit_type_t) &_jit_type_##outtype##_def, \
(jit_type_t) &_jit_type_##intype##_def, 0 } }
static jit_convert_intrinsic_t const convert_intrinsics[] = {
CVT_INTRINSIC(jit_int_to_sbyte, int, int),
CVT_INTRINSIC(jit_int_to_ubyte, int, int),
CVT_INTRINSIC(jit_int_to_short, int, int),
CVT_INTRINSIC(jit_int_to_ushort, int, int),
#ifdef JIT_NATIVE_INT32
CVT_INTRINSIC(jit_int_to_int, int, int),
CVT_INTRINSIC(jit_uint_to_uint, uint, uint),
#else
CVT_INTRINSIC(jit_long_to_int, long, int),
CVT_INTRINSIC(jit_long_to_uint, long, uint),
#endif
CVT_INTRINSIC_CHECK(jit_int_to_sbyte_ovf, int, int),
CVT_INTRINSIC_CHECK(jit_int_to_ubyte_ovf, int, int),
CVT_INTRINSIC_CHECK(jit_int_to_short_ovf, int, int),
CVT_INTRINSIC_CHECK(jit_int_to_ushort_ovf, int, int),
#ifdef JIT_NATIVE_INT32
CVT_INTRINSIC_CHECK(jit_int_to_int_ovf, int, int),
CVT_INTRINSIC_CHECK(jit_uint_to_uint_ovf, uint, uint),
#else
CVT_INTRINSIC_CHECK(jit_long_to_int_ovf, long, int),
CVT_INTRINSIC_CHECK(jit_long_to_uint_ovf, long, uint),
#endif
CVT_INTRINSIC(jit_long_to_uint, long, uint),
CVT_INTRINSIC(jit_int_to_long, int, long),
CVT_INTRINSIC(jit_uint_to_long, uint, long),
CVT_INTRINSIC_CHECK(jit_long_to_uint_ovf, long, uint),
CVT_INTRINSIC_CHECK(jit_long_to_int_ovf, long, int),
CVT_INTRINSIC_CHECK(jit_ulong_to_long_ovf, ulong, long),
CVT_INTRINSIC_CHECK(jit_long_to_ulong_ovf, long, ulong),
CVT_INTRINSIC(jit_float32_to_int, float32, int),
CVT_INTRINSIC(jit_float32_to_uint, float32, uint),
CVT_INTRINSIC(jit_float32_to_long, float32, long),
CVT_INTRINSIC(jit_float32_to_ulong, float32, ulong),
CVT_INTRINSIC_CHECK(jit_float32_to_int_ovf, float32, int),
CVT_INTRINSIC_CHECK(jit_float32_to_uint_ovf, float32, uint),
CVT_INTRINSIC_CHECK(jit_float32_to_long_ovf, float32, long),
CVT_INTRINSIC_CHECK(jit_float32_to_ulong_ovf, float32, ulong),
CVT_INTRINSIC(jit_int_to_float32, int, float32),
CVT_INTRINSIC(jit_uint_to_float32, uint, float32),
CVT_INTRINSIC(jit_long_to_float32, long, float32),
CVT_INTRINSIC(jit_ulong_to_float32, ulong, float32),
CVT_INTRINSIC(jit_float32_to_float64, float32, float64),
CVT_INTRINSIC(jit_float64_to_int, float64, int),
CVT_INTRINSIC(jit_float64_to_uint, float64, uint),
CVT_INTRINSIC(jit_float64_to_long, float64, long),
CVT_INTRINSIC(jit_float64_to_ulong, float64, ulong),
CVT_INTRINSIC_CHECK(jit_float64_to_int_ovf, float64, int),
CVT_INTRINSIC_CHECK(jit_float64_to_uint_ovf, float64, uint),
CVT_INTRINSIC_CHECK(jit_float64_to_long_ovf, float64, long),
CVT_INTRINSIC_CHECK(jit_float64_to_ulong_ovf, float64, ulong),
CVT_INTRINSIC(jit_int_to_float64, int, float64),
CVT_INTRINSIC(jit_uint_to_float64, uint, float64),
CVT_INTRINSIC(jit_long_to_float64, long, float64),
CVT_INTRINSIC(jit_ulong_to_float64, ulong, float64),
CVT_INTRINSIC(jit_float64_to_float32, float64, float32),
CVT_INTRINSIC(jit_nfloat_to_int, nfloat, int),
CVT_INTRINSIC(jit_nfloat_to_uint, nfloat, uint),
CVT_INTRINSIC(jit_nfloat_to_long, nfloat, long),
CVT_INTRINSIC(jit_nfloat_to_ulong, nfloat, ulong),
CVT_INTRINSIC_CHECK(jit_nfloat_to_int_ovf, nfloat, int),
CVT_INTRINSIC_CHECK(jit_nfloat_to_uint_ovf, nfloat, uint),
CVT_INTRINSIC_CHECK(jit_nfloat_to_long_ovf, nfloat, long),
CVT_INTRINSIC_CHECK(jit_nfloat_to_ulong_ovf, nfloat, ulong),
CVT_INTRINSIC(jit_int_to_nfloat, int, nfloat),
CVT_INTRINSIC(jit_uint_to_nfloat, uint, nfloat),
CVT_INTRINSIC(jit_long_to_nfloat, long, nfloat),
CVT_INTRINSIC(jit_ulong_to_nfloat, ulong, nfloat),
CVT_INTRINSIC(jit_nfloat_to_float32, nfloat, float32),
CVT_INTRINSIC(jit_nfloat_to_float64, nfloat, float64),
CVT_INTRINSIC(jit_float32_to_nfloat, float32, nfloat),
CVT_INTRINSIC(jit_float64_to_nfloat, float64, nfloat)
};
static jit_value_t
apply_conversion(jit_function_t func, int oper, jit_value_t value,
jit_type_t result_type)
{
if(oper < sizeof(convert_intrinsics) / sizeof(jit_convert_intrinsic_t)
&& convert_intrinsics[oper - 1].descr.ptr_result_type)
{
func->builder->may_throw = 1;
}
if(_jit_opcode_is_supported(oper))
{
return apply_unary(func, oper, value, result_type);
}
return jit_insn_call_intrinsic(func, convert_intrinsics[oper - 1].name,
convert_intrinsics[oper - 1].func,
&convert_intrinsics[oper - 1].descr,
value, 0);
}
jit_value_t
jit_insn_convert(jit_function_t func, jit_value_t value, jit_type_t type,
int overflow_check)
{
jit_type_t vtype = jit_type_normalize(value->type);
type = jit_type_normalize(type);
if(type == vtype)
{
return value;
}
if(jit_value_is_constant(value))
{
jit_constant_t const_value;
const_value = jit_value_get_constant(value);
if(jit_constant_convert(&const_value, &const_value, type, overflow_check))
{
return jit_value_create_constant(func, &const_value);
}
}
vtype = jit_type_promote_int(vtype);
const jit_convert_info_t *opcode_map = 0;
switch(type->kind)
{
case JIT_TYPE_SBYTE:
{
static jit_convert_info_t const to_sbyte[] = {
{ CVT(JIT_OP_TRUNC_SBYTE, sbyte),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_SBYTE, sbyte),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_TRUNC_SBYTE, sbyte),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_INT, int),
CVT(JIT_OP_CHECK_SBYTE, sbyte),
CVT_NONE },
{ CVT(JIT_OP_LOW_WORD, int),
CVT(JIT_OP_TRUNC_SBYTE, sbyte),
CVT_NONE },
{ CVT(JIT_OP_CHECK_SIGNED_LOW_WORD, int),
CVT(JIT_OP_CHECK_SBYTE, sbyte),
CVT_NONE },
{ CVT(JIT_OP_LOW_WORD, int),
CVT(JIT_OP_TRUNC_SBYTE, sbyte),
CVT_NONE },
{ CVT(JIT_OP_CHECK_LOW_WORD, uint),
CVT(JIT_OP_CHECK_INT, int),
CVT(JIT_OP_CHECK_SBYTE, sbyte) },
{ CVT(JIT_OP_FLOAT32_TO_INT, int),
CVT(JIT_OP_TRUNC_SBYTE, sbyte),
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT32_TO_INT, int),
CVT(JIT_OP_CHECK_SBYTE, sbyte),
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_INT, int),
CVT(JIT_OP_TRUNC_SBYTE, sbyte),
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT64_TO_INT, int),
CVT(JIT_OP_CHECK_SBYTE, sbyte),
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_INT, int),
CVT(JIT_OP_TRUNC_SBYTE, sbyte),
CVT_NONE },
{ CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
CVT(JIT_OP_CHECK_SBYTE, sbyte),
CVT_NONE }
};
opcode_map = to_sbyte;
break;
}
case JIT_TYPE_UBYTE:
{
static jit_convert_info_t const to_ubyte[] = {
{ CVT(JIT_OP_TRUNC_UBYTE, ubyte),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_UBYTE, ubyte),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_TRUNC_UBYTE, ubyte),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_UBYTE, ubyte),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_LOW_WORD, int),
CVT(JIT_OP_TRUNC_UBYTE, ubyte),
CVT_NONE },
{ CVT(JIT_OP_CHECK_SIGNED_LOW_WORD, int),
CVT(JIT_OP_CHECK_UBYTE, ubyte),
CVT_NONE },
{ CVT(JIT_OP_LOW_WORD, int),
CVT(JIT_OP_TRUNC_UBYTE, ubyte),
CVT_NONE },
{ CVT(JIT_OP_CHECK_LOW_WORD, uint),
CVT(JIT_OP_CHECK_UBYTE, ubyte),
CVT_NONE },
{ CVT(JIT_OP_FLOAT32_TO_INT, int),
CVT(JIT_OP_TRUNC_UBYTE, ubyte),
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT32_TO_INT, int),
CVT(JIT_OP_CHECK_UBYTE, ubyte),
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_INT, int),
CVT(JIT_OP_TRUNC_UBYTE, ubyte),
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT64_TO_INT, int),
CVT(JIT_OP_CHECK_UBYTE, ubyte),
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_INT, int),
CVT(JIT_OP_TRUNC_UBYTE, ubyte),
CVT_NONE },
{ CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
CVT(JIT_OP_CHECK_UBYTE, ubyte),
CVT_NONE }
};
opcode_map = to_ubyte;
break;
}
case JIT_TYPE_SHORT:
{
static jit_convert_info_t const to_short[] = {
{ CVT(JIT_OP_TRUNC_SHORT, short),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_SHORT, short),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_TRUNC_SHORT, short),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_INT, int),
CVT(JIT_OP_CHECK_SHORT, short),
CVT_NONE },
{ CVT(JIT_OP_LOW_WORD, int),
CVT(JIT_OP_TRUNC_SHORT, short),
CVT_NONE },
{ CVT(JIT_OP_CHECK_SIGNED_LOW_WORD, int),
CVT(JIT_OP_CHECK_SHORT, short),
CVT_NONE },
{ CVT(JIT_OP_LOW_WORD, int),
CVT(JIT_OP_TRUNC_SHORT, short),
CVT_NONE },
{ CVT(JIT_OP_CHECK_LOW_WORD, uint),
CVT(JIT_OP_CHECK_INT, int),
CVT(JIT_OP_CHECK_SHORT, short)},
{ CVT(JIT_OP_FLOAT32_TO_INT, int),
CVT(JIT_OP_TRUNC_SHORT, short),
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT32_TO_INT, int),
CVT(JIT_OP_CHECK_SHORT, short),
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_INT, int),
CVT(JIT_OP_TRUNC_SHORT, short),
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT64_TO_INT, int),
CVT(JIT_OP_CHECK_SHORT, short),
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_INT, int),
CVT(JIT_OP_TRUNC_SHORT, short),
CVT_NONE },
{ CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
CVT(JIT_OP_CHECK_SHORT, short),
CVT_NONE }
};
opcode_map = to_short;
break;
}
case JIT_TYPE_USHORT:
{
static jit_convert_info_t const to_ushort[] = {
{ CVT(JIT_OP_TRUNC_USHORT, ushort),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_USHORT, ushort),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_TRUNC_USHORT, ushort),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_USHORT, ushort),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_LOW_WORD, int),
CVT(JIT_OP_TRUNC_USHORT, ushort),
CVT_NONE },
{ CVT(JIT_OP_CHECK_SIGNED_LOW_WORD, int),
CVT(JIT_OP_CHECK_USHORT, ushort),
CVT_NONE },
{ CVT(JIT_OP_LOW_WORD, int),
CVT(JIT_OP_TRUNC_USHORT, ushort),
CVT_NONE },
{ CVT(JIT_OP_CHECK_LOW_WORD, uint),
CVT(JIT_OP_CHECK_USHORT, ushort),
CVT_NONE },
{ CVT(JIT_OP_FLOAT32_TO_INT, int),
CVT(JIT_OP_TRUNC_USHORT, ushort),
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT32_TO_INT, int),
CVT(JIT_OP_CHECK_USHORT, ushort),
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_INT, int),
CVT(JIT_OP_TRUNC_USHORT, ushort),
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT64_TO_INT, int),
CVT(JIT_OP_CHECK_USHORT, ushort),
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_INT, int),
CVT(JIT_OP_TRUNC_USHORT, ushort),
CVT_NONE },
{ CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
CVT(JIT_OP_CHECK_USHORT, ushort),
CVT_NONE }
};
opcode_map = to_ushort;
break;
}
case JIT_TYPE_INT:
{
static jit_convert_info_t const to_int[] = {
{ CVT(JIT_OP_COPY_INT, int),
CVT_NONE,
CVT_NONE},
{ CVT(JIT_OP_COPY_INT, int),
CVT_NONE,
CVT_NONE},
#ifndef JIT_NATIVE_INT32
{ CVT(JIT_OP_TRUNC_INT, int),
CVT_NONE,
CVT_NONE},
#else
{ CVT(JIT_OP_COPY_INT, int),
CVT_NONE,
CVT_NONE},
#endif
{ CVT(JIT_OP_CHECK_INT, int),
CVT_NONE,
CVT_NONE},
{ CVT(JIT_OP_LOW_WORD, int),
#ifndef JIT_NATIVE_INT32
CVT(JIT_OP_TRUNC_INT, int),
#else
CVT_NONE,
#endif
CVT_NONE},
{ CVT(JIT_OP_CHECK_SIGNED_LOW_WORD, int),
CVT_NONE,
CVT_NONE},
{ CVT(JIT_OP_LOW_WORD, int),
#ifndef JIT_NATIVE_INT32
CVT(JIT_OP_TRUNC_INT, int),
#else
CVT_NONE,
#endif
CVT_NONE},
{ CVT(JIT_OP_CHECK_LOW_WORD, uint),
CVT(JIT_OP_CHECK_INT, int),
CVT_NONE },
{ CVT(JIT_OP_FLOAT32_TO_INT, int),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT32_TO_INT, int),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_INT, int),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT64_TO_INT, int),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_INT, int),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
CVT_NONE,
CVT_NONE }
};
opcode_map = to_int;
break;
}
case JIT_TYPE_UINT:
{
static jit_convert_info_t const to_uint[] = {
#ifndef JIT_NATIVE_INT32
{ CVT(JIT_OP_TRUNC_UINT, uint),
CVT_NONE,
CVT_NONE },
#else
{ CVT(JIT_OP_COPY_INT, uint),
CVT_NONE,
CVT_NONE },
#endif
{ CVT(JIT_OP_CHECK_UINT, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_INT, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_INT, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_LOW_WORD, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_LOW_WORD, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_LOW_WORD, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_LOW_WORD, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT32_TO_UINT, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT32_TO_UINT, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_UINT, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT64_TO_UINT, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_UINT, uint),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_NFLOAT_TO_UINT, uint),
CVT_NONE,
CVT_NONE }
};
opcode_map = to_uint;
break;
}
case JIT_TYPE_LONG:
{
static jit_convert_info_t const to_long[] = {
{ CVT(JIT_OP_EXPAND_INT, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_EXPAND_INT, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_EXPAND_UINT, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_EXPAND_UINT, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_LONG, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_LONG, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_LONG, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_LONG, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT32_TO_LONG, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT32_TO_LONG, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_LONG, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT64_TO_LONG, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_LONG, long),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_NFLOAT_TO_LONG, long),
CVT_NONE,
CVT_NONE }
};
opcode_map = to_long;
break;
}
case JIT_TYPE_ULONG:
{
static jit_convert_info_t const to_ulong[] = {
{ CVT(JIT_OP_EXPAND_INT, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_UINT, uint),
CVT(JIT_OP_EXPAND_UINT, ulong),
CVT_NONE },
{ CVT(JIT_OP_EXPAND_UINT, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_EXPAND_UINT, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_LONG, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_ULONG, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_LONG, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_LONG, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT32_TO_ULONG, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT32_TO_ULONG, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_ULONG, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_FLOAT64_TO_ULONG, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_ULONG, ulong),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_CHECK_NFLOAT_TO_ULONG, ulong),
CVT_NONE,
CVT_NONE }
};
opcode_map = to_ulong;
break;
}
case JIT_TYPE_FLOAT32:
{
static jit_convert_info_t const to_float32[] = {
{ CVT(JIT_OP_INT_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_INT_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_UINT_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_UINT_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_LONG_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_LONG_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_ULONG_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_ULONG_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
CVT_NONE,
CVT_NONE }
};
opcode_map = to_float32;
break;
}
case JIT_TYPE_FLOAT64:
{
static jit_convert_info_t const to_float64[] = {
{ CVT(JIT_OP_INT_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_INT_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_UINT_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_UINT_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_LONG_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_LONG_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_ULONG_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_ULONG_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT32_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT32_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
CVT_NONE,
CVT_NONE }
};
opcode_map = to_float64;
break;
}
case JIT_TYPE_NFLOAT:
{
static jit_convert_info_t const to_nfloat[] = {
{ CVT(JIT_OP_INT_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_INT_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_UINT_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_UINT_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_LONG_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_LONG_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_ULONG_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_ULONG_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE },
{ CVT(JIT_OP_COPY_NFLOAT, nfloat),
CVT_NONE,
CVT_NONE }
};
opcode_map = to_nfloat;
break;
}
}
if(opcode_map)
{
switch(vtype->kind)
{
case JIT_TYPE_UINT: opcode_map += 2; break;
case JIT_TYPE_LONG: opcode_map += 4; break;
case JIT_TYPE_ULONG: opcode_map += 6; break;
case JIT_TYPE_FLOAT32: opcode_map += 8; break;
case JIT_TYPE_FLOAT64: opcode_map += 10; break;
case JIT_TYPE_NFLOAT: opcode_map += 12; break;
}
if(overflow_check)
{
opcode_map += 1;
}
if(opcode_map->cvt1)
{
value = apply_conversion(func, opcode_map->cvt1, value,
opcode_map->type1);
}
if(opcode_map->cvt2 && value)
{
value = apply_conversion(func, opcode_map->cvt2, value,
opcode_map->type2);
}
if(opcode_map->cvt3 && value)
{
value = apply_conversion(func, opcode_map->cvt3, value,
opcode_map->type3);
}
}
return value;
}
static int
convert_call_parameters(jit_function_t func, jit_type_t signature,
jit_value_t *args, unsigned int num_args,
jit_value_t *new_args)
{
unsigned int param;
for(param = 0; param < num_args; ++param)
{
new_args[param] = jit_insn_convert(func, args[param],
jit_type_get_param(signature, param),
0);
if (!new_args[param])
return 0;
}
return 1;
}
static int
setup_eh_frame_for_call(jit_function_t func, int flags)
{
#if !defined(JIT_BACKEND_INTERP)
jit_type_t type;
jit_value_t args[2];
jit_insn_t insn;
if((flags & JIT_CALL_TAIL) != 0 && func->has_try)
{
type = jit_type_create_signature(jit_abi_cdecl, jit_type_void, 0, 0, 1);
if(!type)
{
return 0;
}
jit_insn_call_native(func, "_jit_unwind_pop_setjmp",
(void *) _jit_unwind_pop_setjmp, type,
0, 0, JIT_CALL_NOTHROW);
jit_type_free(type);
}
if((flags & (JIT_CALL_NOTHROW | JIT_CALL_TAIL)) != 0)
{
return 1;
}
func->builder->may_throw = 1;
#if JIT_APPLY_BROKEN_FRAME_BUILTINS != 0
{
jit_value_t eh_frame_info;
jit_type_t params[2];
if((eh_frame_info = func->builder->eh_frame_info) == 0)
{
type = jit_type_create_struct(0, 0, 0);
if(!type)
{
return 0;
}
jit_type_set_size_and_alignment(type,
sizeof(struct jit_backtrace),
sizeof(void *));
eh_frame_info = jit_value_create(func, type);
jit_type_free(type);
if(!eh_frame_info)
{
return 0;
}
func->builder->eh_frame_info = eh_frame_info;
}
args[1] = jit_value_create(func, jit_type_void_ptr);
if(!args[1])
{
return 0;
}
insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = JIT_OP_LOAD_PC;
insn->dest = args[1];
args[0] = jit_insn_address_of(func, eh_frame_info);
if(!args[0])
{
return 0;
}
params[0] = jit_type_void_ptr;
params[1] = jit_type_void_ptr;
type = jit_type_create_signature(jit_abi_cdecl, jit_type_void, params, 2, 1);
if(!type)
{
return 0;
}
jit_insn_call_native(func, "_jit_backtrace_push",
(void *) _jit_backtrace_push, type,
args, 2, JIT_CALL_NOTHROW);
jit_type_free(type);
}
#endif
if(func->builder->setjmp_value != 0)
{
args[0] = jit_value_create(func, jit_type_void_ptr);
if(!args[0])
{
return 0;
}
insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = JIT_OP_LOAD_PC;
insn->dest = args[0];
jit_value_t addr = jit_insn_address_of(func, func->builder->setjmp_value);
if(!addr)
{
return 0;
}
if(!jit_insn_store_relative(func, addr, jit_jmp_catch_pc_offset, args[0]))
{
return 0;
}
}
return 1;
#else
if((flags & (JIT_CALL_NOTHROW | JIT_CALL_TAIL)) == 0)
{
func->builder->may_throw = 1;
}
return 1;
#endif
}
static int
restore_eh_frame_after_call(jit_function_t func, int flags)
{
#if !defined(JIT_BACKEND_INTERP)
if((flags & (JIT_CALL_NOTHROW | JIT_CALL_NORETURN | JIT_CALL_TAIL)) != 0)
{
return 1;
}
#if JIT_APPLY_BROKEN_FRAME_BUILTINS != 0
jit_type_t type = jit_type_create_signature(jit_abi_cdecl, jit_type_void, 0, 0, 0);
if(!type)
{
return 0;
}
jit_insn_call_native(func, "_jit_backtrace_pop",
(void *) _jit_backtrace_pop, type,
0, 0, JIT_CALL_NOTHROW);
jit_type_free(type);
#endif
if(func->builder->setjmp_value != 0)
{
jit_value_t null = jit_value_create_nint_constant(func, jit_type_void_ptr, 0);
jit_value_t addr = jit_insn_address_of(func, func->builder->setjmp_value);
if(!null || !addr)
{
return 0;
}
if(!jit_insn_store_relative(func, addr, jit_jmp_catch_pc_offset, null))
{
return 0;
}
}
return 1;
#else
return 1;
#endif
}
static int
signature_identical(jit_type_t type1, jit_type_t type2)
{
if(type1 == type2)
{
return 1;
}
type1 = jit_type_remove_tags(type1);
type2 = jit_type_remove_tags(type2);
if(!type1 || !type2)
{
return 0;
}
if(type1->kind == JIT_TYPE_PTR)
{
type1 = jit_type_normalize(type1);
}
if(type2->kind == JIT_TYPE_PTR)
{
type2 = jit_type_normalize(type2);
}
#ifdef JIT_NFLOAT_IS_DOUBLE
if((type1->kind == JIT_TYPE_FLOAT64 || type1->kind == JIT_TYPE_NFLOAT) &&
(type2->kind == JIT_TYPE_FLOAT64 || type2->kind == JIT_TYPE_NFLOAT))
{
return 1;
}
#endif
if(type1->kind != type2->kind)
{
return 0;
}
if(type1->kind == JIT_TYPE_STRUCT || type1->kind == JIT_TYPE_UNION)
{
return (jit_type_get_size(type1) == jit_type_get_size(type2) &&
jit_type_get_alignment(type1) == jit_type_get_alignment(type2));
}
if(type1->kind == JIT_TYPE_SIGNATURE)
{
if(type1->abi != type2->abi)
{
return 0;
}
if(!signature_identical(type1->sub_type, type2->sub_type))
{
return 0;
}
if(type1->num_components != type2->num_components)
{
return 0;
}
unsigned int param;
for(param = 0; param < type1->num_components; ++param)
{
if(!signature_identical(type1->components[param].type,
type2->components[param].type))
{
return 0;
}
}
}
return 1;
}
static int
create_call_setup_insns(jit_function_t func, jit_function_t callee,
jit_type_t signature,
jit_value_t *args, unsigned int num_args,
int is_nested, jit_value_t parent_frame,
jit_value_t *struct_return, int flags)
{
jit_value_t *new_args;
unsigned int arg_num;
if((flags & JIT_CALL_TAIL) != 0 && num_args > 0)
{
new_args = (jit_value_t *) alloca(sizeof(jit_value_t) * num_args);
for(arg_num = 0; arg_num < num_args; ++arg_num)
{
jit_value_t value = args[arg_num];
if(value && value->is_parameter)
{
value = jit_insn_dup(func, value);
if(!value)
{
return 0;
}
}
new_args[arg_num] = value;
}
args = new_args;
}
if((flags & JIT_CALL_TAIL) != 0)
{
for(arg_num = 0; arg_num < num_args; ++arg_num)
{
if(!jit_insn_store(func, jit_value_get_param(func, arg_num),
args[arg_num]))
{
return 0;
}
}
*struct_return = 0;
return 1;
}
return _jit_create_call_setup_insns(func, signature, args, num_args,
is_nested, parent_frame, struct_return,
flags);
}
static jit_value_t
handle_return(jit_function_t func,
jit_type_t signature,
int flags, int is_nested,
jit_value_t *args, unsigned int num_args,
jit_value_t return_value)
{
if((flags & (JIT_CALL_NORETURN | JIT_CALL_TAIL)) != 0)
{
func->builder->current_block->ends_in_dead = 1;
}
if((flags & JIT_CALL_NOTHROW) == 0)
{
if(!jit_insn_new_block(func))
{
return 0;
}
}
if(!return_value)
{
return_value = jit_value_create(func, jit_type_get_return(signature));
if(!return_value)
{
return 0;
}
}
if((flags & JIT_CALL_TAIL) == 0)
{
if(!_jit_create_call_return_insns(func, signature, args, num_args,
return_value, is_nested))
{
return 0;
}
}
if(!restore_eh_frame_after_call(func, flags))
{
return 0;
}
return return_value;
}
jit_value_t
jit_insn_call(jit_function_t func, const char *name, jit_function_t jit_func,
jit_type_t signature, jit_value_t *args, unsigned int num_args,
int flags)
{
int is_nested;
jit_value_t parent_frame;
jit_value_t return_value;
jit_label_t entry_point;
jit_label_t label_end;
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!signature)
{
signature = jit_func->signature;
}
if((flags & JIT_CALL_TAIL) != 0)
{
if(func->nested_parent || jit_func->nested_parent)
{
flags &= ~JIT_CALL_TAIL;
}
else if(!signature_identical(signature, func->signature))
{
flags &= ~JIT_CALL_TAIL;
}
}
if(jit_func->nested_parent)
{
is_nested = 1;
parent_frame = jit_insn_get_parent_frame_pointer_of(func, jit_func);
if(!parent_frame)
{
return 0;
}
}
else
{
is_nested = 0;
parent_frame = 0;
}
jit_value_t *new_args;
if(num_args > 0)
{
new_args = (jit_value_t *) alloca(sizeof(jit_value_t) * num_args);
if(!convert_call_parameters(func, signature, args, num_args, new_args))
{
return 0;
}
}
else
{
new_args = args;
}
if(jit_func->no_throw)
{
flags |= JIT_CALL_NOTHROW;
}
if(jit_func->no_return)
{
flags |= JIT_CALL_NORETURN;
}
if(!setup_eh_frame_for_call(func, flags))
{
return 0;
}
if(!create_call_setup_insns(func, jit_func, signature, new_args, num_args,
is_nested, parent_frame, &return_value, flags))
{
return 0;
}
if((flags & JIT_CALL_TAIL) != 0 && func == jit_func)
{
entry_point = jit_label_undefined;
label_end = jit_label_undefined;
if(!jit_insn_branch(func, &entry_point))
{
return 0;
}
if(!jit_insn_label_tight(func, &entry_point))
{
return 0;
}
if(!jit_insn_label(func, &label_end))
{
return 0;
}
if(!jit_insn_move_blocks_to_start(func, entry_point, label_end))
{
return 0;
}
}
else
{
func->builder->non_leaf = 1;
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
if((flags & JIT_CALL_TAIL) != 0)
{
func->builder->has_tail_call = 1;
insn->opcode = JIT_OP_CALL_TAIL;
}
else
{
insn->opcode = JIT_OP_CALL;
}
insn->flags = JIT_INSN_DEST_IS_FUNCTION | JIT_INSN_VALUE1_IS_NAME;
insn->dest = (jit_value_t) jit_func;
insn->value1 = (jit_value_t) name;
}
return handle_return(func, signature, flags, is_nested, new_args, num_args, return_value);
}
jit_value_t
jit_insn_call_nested_indirect(jit_function_t func, jit_value_t value,
jit_value_t parent_frame, jit_type_t signature, jit_value_t *args,
unsigned int num_args, int flags)
{
int is_nested = parent_frame ? 1 : 0;
if(!_jit_function_ensure_builder(func))
{
return 0;
}
#if defined(JIT_BACKEND_INTERP)
flags &= ~JIT_CALL_TAIL;
#else
if((flags & JIT_CALL_TAIL) != 0)
{
if(is_nested || func->nested_parent)
{
flags &= ~JIT_CALL_TAIL;
}
else if(!signature_identical(signature, func->signature))
{
flags &= ~JIT_CALL_TAIL;
}
}
#endif
flags |= JIT_CALL_NATIVE;
jit_value_t *new_args;
if(num_args > 0)
{
new_args = (jit_value_t *) alloca(sizeof(jit_value_t) * num_args);
if(!convert_call_parameters(func, signature, args, num_args, new_args))
{
return 0;
}
}
else
{
new_args = args;
}
if(!setup_eh_frame_for_call(func, flags))
{
return 0;
}
jit_value_t return_value;
if(!create_call_setup_insns(func, 0, signature, new_args, num_args,
is_nested, parent_frame, &return_value, flags))
{
return 0;
}
if(!_jit_setup_indirect_pointer(func, value))
{
return 0;
}
func->builder->non_leaf = 1;
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
if((flags & JIT_CALL_TAIL) != 0)
{
func->builder->has_tail_call = 1;
insn->opcode = JIT_OP_CALL_INDIRECT_TAIL;
}
else
{
insn->opcode = JIT_OP_CALL_INDIRECT;
}
insn->flags = JIT_INSN_VALUE2_IS_SIGNATURE;
insn->value1 = value;
jit_value_ref(func, value);
insn->value2 = (jit_value_t) jit_type_copy(signature);
return handle_return(func, signature, flags, is_nested, new_args, num_args,
return_value);
}
jit_value_t
jit_insn_call_indirect(jit_function_t func, jit_value_t value,
jit_type_t signature, jit_value_t *args,
unsigned int num_args, int flags)
{
return jit_insn_call_nested_indirect(func, value, 0, signature,
args, num_args, flags);
}
jit_value_t
jit_insn_call_indirect_vtable(jit_function_t func, jit_value_t value, jit_type_t signature,
jit_value_t *args, unsigned int num_args, int flags)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if((flags & JIT_CALL_TAIL) != 0)
{
if(func->nested_parent)
{
flags &= ~JIT_CALL_TAIL;
}
else if(!signature_identical(signature, func->signature))
{
flags &= ~JIT_CALL_TAIL;
}
}
jit_value_t *new_args;
if(num_args > 0)
{
new_args = (jit_value_t *) alloca(sizeof(jit_value_t) * num_args);
if(!convert_call_parameters(func, signature, args, num_args, new_args))
{
return 0;
}
}
else
{
new_args = args;
}
if(!setup_eh_frame_for_call(func, flags))
{
return 0;
}
jit_value_t return_value;
if(!create_call_setup_insns(func, 0, signature, new_args, num_args,
0, 0, &return_value, flags))
{
return 0;
}
if(!_jit_setup_indirect_pointer(func, value))
{
return 0;
}
func->builder->non_leaf = 1;
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
if((flags & JIT_CALL_TAIL) != 0)
{
func->builder->has_tail_call = 1;
insn->opcode = JIT_OP_CALL_VTABLE_PTR_TAIL;
}
else
{
insn->opcode = JIT_OP_CALL_VTABLE_PTR;
}
insn->value1 = value;
jit_value_ref(func, value);
return handle_return(func, signature, flags, 0, new_args, num_args, return_value);
}
jit_value_t
jit_insn_call_native(jit_function_t func, const char *name, void *native_func,
jit_type_t signature, jit_value_t *args, unsigned int num_args, int flags)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
#if defined(JIT_BACKEND_INTERP)
flags &= ~JIT_CALL_TAIL;
#else
if((flags & JIT_CALL_TAIL) != 0)
{
if(func->nested_parent)
{
flags &= ~JIT_CALL_TAIL;
}
else if(!signature_identical(signature, func->signature))
{
flags &= ~JIT_CALL_TAIL;
}
}
#endif
flags |= JIT_CALL_NATIVE;
jit_value_t *new_args;
if(num_args > 0)
{
new_args = (jit_value_t *) alloca(sizeof(jit_value_t) * num_args);
if(!convert_call_parameters(func, signature, args, num_args, new_args))
{
return 0;
}
}
else
{
new_args = args;
}
if(!setup_eh_frame_for_call(func, flags))
{
return 0;
}
jit_value_t return_value;
if(!create_call_setup_insns(func, 0, signature, new_args, num_args,
0, 0, &return_value, flags))
{
return 0;
}
func->builder->non_leaf = 1;
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
if((flags & JIT_CALL_TAIL) != 0)
{
func->builder->has_tail_call = 1;
insn->opcode = JIT_OP_CALL_EXTERNAL_TAIL;
}
else
{
insn->opcode = JIT_OP_CALL_EXTERNAL;
}
insn->flags = JIT_INSN_DEST_IS_NATIVE | JIT_INSN_VALUE1_IS_NAME;
insn->dest = (jit_value_t) native_func;
insn->value1 = (jit_value_t) name;
#ifdef JIT_BACKEND_INTERP
insn->flags |= JIT_INSN_VALUE2_IS_SIGNATURE;
insn->value2 = (jit_value_t) jit_type_copy(signature);
#endif
return_value = handle_return(func, signature, flags, 0, new_args, num_args, return_value);
jit_type_t return_type = jit_type_remove_tags(return_value->type);
switch(return_type->kind)
{
case JIT_TYPE_SBYTE:
return_value = apply_conversion(func, JIT_OP_TRUNC_SBYTE, return_value,
return_type);
break;
case JIT_TYPE_UBYTE:
return_value = apply_conversion(func, JIT_OP_TRUNC_UBYTE, return_value,
return_type);
break;
case JIT_TYPE_SHORT:
return_value = apply_conversion(func, JIT_OP_TRUNC_SHORT, return_value,
return_type);
break;
case JIT_TYPE_USHORT:
return_value = apply_conversion(func, JIT_OP_TRUNC_USHORT, return_value,
return_type);
break;
}
return return_value;
}
jit_value_t
jit_insn_call_intrinsic(jit_function_t func, const char *name, void *intrinsic_func,
const jit_intrinsic_descr_t *descriptor, jit_value_t arg1,
jit_value_t arg2)
{
jit_type_t signature;
jit_type_t param_types[3];
jit_value_t param_values[3];
jit_value_t return_value;
jit_value_t temp_value;
jit_value_t cond_value;
jit_label_t label;
jit_constant_t const1;
jit_constant_t const2;
jit_constant_t return_const;
jit_constant_t temp_const;
void *apply_args[3];
if(!_jit_function_ensure_builder(func))
{
return 0;
}
arg1 = jit_insn_convert(func, arg1, descriptor->arg1_type, 0);
if(!arg1)
{
return 0;
}
if(arg2)
{
arg2 = jit_insn_convert(func, arg2, descriptor->arg2_type, 0);
if(!arg2)
{
return 0;
}
}
if(descriptor->ptr_result_type)
{
return_value = jit_value_create(func, descriptor->ptr_result_type);
if(!return_value)
{
return 0;
}
}
else
{
return_value = 0;
}
unsigned int num_params = 0;
if(return_value)
{
temp_value = jit_insn_address_of(func, return_value);
if(!temp_value)
{
return 0;
}
param_types[num_params] = jit_value_get_type(temp_value);
param_values[num_params] = temp_value;
++num_params;
}
param_types[num_params] = jit_value_get_type(arg1);
param_values[num_params] = arg1;
++num_params;
if(arg2)
{
param_types[num_params] = jit_value_get_type(arg2);
param_values[num_params] = arg2;
++num_params;
}
signature = jit_type_create_signature(jit_abi_cdecl, descriptor->return_type,
param_types, num_params, 1);
if(!signature)
{
return 0;
}
if(jit_value_is_constant(arg1)
&& (!arg2 || jit_value_is_constant(arg2))
&& !jit_context_get_meta_numeric(func->context, JIT_OPTION_DONT_FOLD))
{
const1 = jit_value_get_constant(arg1);
const2 = jit_value_get_constant(arg2);
if(return_value)
{
jit_int result;
return_const.type = descriptor->ptr_result_type;
temp_const.un.ptr_value = &return_const.un;
apply_args[0] = &temp_const.un;
apply_args[1] = &const1.un;
apply_args[2] = &const2.un;
jit_apply(signature, intrinsic_func, apply_args, num_params,
&result);
if(result >= 1)
{
jit_type_free(signature);
return jit_value_create_constant(func, &return_const);
}
}
else
{
return_const.type = descriptor->return_type;
apply_args[0] = &const1.un;
apply_args[1] = &const2.un;
jit_apply(signature, intrinsic_func, apply_args, num_params,
&return_const.un);
jit_type_free(signature);
return jit_value_create_constant(func, &return_const);
}
}
temp_value = jit_insn_call_native(func, name, intrinsic_func, signature,
param_values, num_params, JIT_CALL_NOTHROW);
if(!temp_value)
{
jit_type_free(signature);
return 0;
}
jit_type_free(signature);
if(!return_value)
{
return temp_value;
}
cond_value = jit_value_create_nint_constant(func, jit_type_int, 1);
cond_value = jit_insn_ge(func, temp_value, cond_value);
if(!cond_value)
{
return 0;
}
label = jit_label_undefined;
if(!jit_insn_branch_if(func, cond_value, &label))
{
return 0;
}
param_types[0] = jit_type_int;
signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void,
param_types, 1, 1);
if(!signature)
{
return 0;
}
param_values[0] = temp_value;
jit_insn_call_native(func, "jit_exception_builtin",
(void *) jit_exception_builtin, signature,
param_values, 1, JIT_CALL_NORETURN);
jit_type_free(signature);
if(!jit_insn_label_tight(func, &label))
{
return 0;
}
return return_value;
}
int
jit_insn_incoming_reg(jit_function_t func, jit_value_t value, int reg)
{
jit_value_t reg_value = jit_value_create_nint_constant(func, jit_type_int, reg);
if(!reg_value)
{
return 0;
}
if(value->is_parameter)
{
value->is_reg_parameter = 1;
}
return create_note(func, JIT_OP_INCOMING_REG, value, reg_value);
}
int
jit_insn_incoming_frame_posn(jit_function_t func, jit_value_t value,
jit_nint frame_offset)
{
jit_value_t frame_offset_value;
if(!value->has_frame_offset)
{
value->has_frame_offset = 1;
value->frame_offset = frame_offset;
}
frame_offset_value
= jit_value_create_nint_constant(func, jit_type_int, frame_offset);
if(!frame_offset_value)
{
return 0;
}
return create_note(func, JIT_OP_INCOMING_FRAME_POSN, value, frame_offset_value);
}
int
jit_insn_outgoing_reg(jit_function_t func, jit_value_t value, int reg)
{
jit_value_t reg_value = jit_value_create_nint_constant(func, jit_type_int, reg);
if(!reg_value)
{
return 0;
}
return create_note(func, JIT_OP_OUTGOING_REG, value, reg_value);
}
int
jit_insn_outgoing_frame_posn(jit_function_t func, jit_value_t value,
jit_nint frame_offset)
{
jit_value_t frame_pointer;
frame_pointer = jit_insn_get_frame_pointer(func);
if(!frame_pointer)
{
return 0;
}
return jit_insn_store_relative(func, frame_pointer, frame_offset, value);
}
int
jit_insn_return_reg(jit_function_t func, jit_value_t value, int reg)
{
jit_value_t reg_value = jit_value_create_nint_constant(func, jit_type_int, reg);
if(!reg_value)
{
return 0;
}
return create_note(func, JIT_OP_RETURN_REG, value, reg_value);
}
int
jit_insn_flush_struct(jit_function_t func, jit_value_t value)
{
if(value)
{
jit_value_set_addressable(value);
}
return create_unary_note(func, JIT_OP_FLUSH_SMALL_STRUCT, value);
}
jit_value_t
jit_insn_get_frame_pointer(jit_function_t func)
{
return create_dest_note(func, JIT_OP_RETRIEVE_FRAME_POINTER,
jit_type_void_ptr);
}
static jit_value_t
find_frame_of(jit_function_t func, jit_function_t target,
jit_function_t func_start, jit_value_t frame_start)
{
int nesting_level = 0;
jit_function_t current_func = func_start;
while(current_func != 0 && current_func != target)
{
if(!_jit_function_ensure_builder(current_func))
{
return 0;
}
if(!current_func->parent_frame)
{
return 0;
}
#ifdef JIT_BACKEND_INTERP
if(!current_func->arguments_pointer)
{
current_func->arguments_pointer = jit_value_create(current_func,
jit_type_void_ptr);
if(!current_func->arguments_pointer)
{
return 0;
}
}
#endif
current_func = current_func->nested_parent;
nesting_level++;
}
if(!current_func)
{
return 0;
}
current_func = func_start;
while(frame_start != 0 && nesting_level-- > 0)
{
frame_start = apply_binary(func, JIT_OP_IMPORT, frame_start,
current_func->parent_frame, jit_type_void_ptr);
frame_start = jit_insn_load_relative(func, frame_start, 0,
jit_type_void_ptr);
current_func = current_func->nested_parent;
}
if(!frame_start)
{
return 0;
}
return frame_start;
}
jit_value_t
jit_insn_get_parent_frame_pointer_of(jit_function_t func, jit_function_t target)
{
if(func == target->nested_parent)
{
return jit_insn_get_frame_pointer(func);
}
else
{
return find_frame_of(func, target->nested_parent,
func->nested_parent, func->parent_frame);
}
}
jit_value_t
jit_insn_import(jit_function_t func, jit_value_t value)
{
jit_function_t value_func;
jit_value_t value_frame;
jit_type_t result_type;
jit_value_t result;
if(!_jit_function_ensure_builder(func))
{
return 0;
}
value_func = jit_value_get_function(value);
if(value_func == func)
{
return jit_insn_address_of(func, value);
}
#ifdef JIT_BACKEND_INTERP
if(!value_func->arguments_pointer)
{
value_func->arguments_pointer = jit_value_create(value_func,
jit_type_void_ptr);
if(!value_func->arguments_pointer)
{
return 0;
}
}
#endif
result_type = jit_type_create_pointer(jit_value_get_type(value), 1);
if(!result_type)
{
return 0;
}
if(value_func == func->cached_parent && func->cached_parent_frame)
{
value_frame = func->cached_parent_frame;
}
else
{
value_frame = find_frame_of(func, value_func,
func->nested_parent, func->parent_frame);
func->cached_parent = value_func;
func->cached_parent_frame = value_frame;
}
if(!value_frame)
{
jit_type_free(result_type);
return 0;
}
result = apply_binary(func, JIT_OP_IMPORT, value_frame, value, result_type);
jit_type_free(result_type);
return result;
}
int
jit_insn_push(jit_function_t func, jit_value_t value)
{
jit_type_t type = jit_value_get_type(value);
type = jit_type_promote_int(jit_type_normalize(type));
jit_value_t size_value;
switch(type->kind)
{
case JIT_TYPE_SBYTE:
case JIT_TYPE_UBYTE:
case JIT_TYPE_SHORT:
case JIT_TYPE_USHORT:
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
return create_unary_note(func, JIT_OP_PUSH_INT, value);
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
return create_unary_note(func, JIT_OP_PUSH_LONG, value);
case JIT_TYPE_FLOAT32:
return create_unary_note(func, JIT_OP_PUSH_FLOAT32, value);
case JIT_TYPE_FLOAT64:
return create_unary_note(func, JIT_OP_PUSH_FLOAT64, value);
case JIT_TYPE_NFLOAT:
return create_unary_note(func, JIT_OP_PUSH_NFLOAT, value);
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
value = jit_insn_address_of(func, value);
size_value = jit_value_create_nint_constant(func, jit_type_nint,
jit_type_get_size(type));
if(!value || !size_value)
{
return 0;
}
return create_note(func, JIT_OP_PUSH_STRUCT, value, size_value);
}
return 1;
}
int
jit_insn_push_ptr(jit_function_t func, jit_value_t value, jit_type_t type)
{
jit_value_t size_value;
switch(jit_type_remove_tags(type)->kind)
{
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
size_value = jit_value_create_nint_constant(func, jit_type_nint,
jit_type_get_size(type));
if(!size_value)
{
return 0;
}
return create_note(func, JIT_OP_PUSH_STRUCT, value, size_value);
default:
value = jit_insn_load_relative(func, value, 0, type);
if(!value)
{
return 0;
}
return jit_insn_push(func, value);
}
}
int
jit_insn_set_param(jit_function_t func, jit_value_t value, jit_nint offset)
{
jit_type_t type = jit_value_get_type(value);
type = jit_type_promote_int(jit_type_normalize(type));
jit_value_t offset_value, size_value;
offset_value = jit_value_create_nint_constant(func, jit_type_nint, offset);
if(!offset_value)
{
return 0;
}
switch(type->kind)
{
case JIT_TYPE_SBYTE:
case JIT_TYPE_UBYTE:
case JIT_TYPE_SHORT:
case JIT_TYPE_USHORT:
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
return create_note(func, JIT_OP_SET_PARAM_INT, value, offset_value);
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
return create_note(func, JIT_OP_SET_PARAM_LONG, value, offset_value);
case JIT_TYPE_FLOAT32:
return create_note(func, JIT_OP_SET_PARAM_FLOAT32, value, offset_value);
case JIT_TYPE_FLOAT64:
return create_note(func, JIT_OP_SET_PARAM_FLOAT64, value, offset_value);
case JIT_TYPE_NFLOAT:
return create_note(func, JIT_OP_SET_PARAM_NFLOAT, value, offset_value);
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
value = jit_insn_address_of(func, value);
size_value = jit_value_create_nint_constant(func, jit_type_nint,
jit_type_get_size(type));
if(!value || !size_value)
{
return 0;
}
return apply_ternary(func, JIT_OP_SET_PARAM_STRUCT, offset_value, value,
size_value);
}
return 1;
}
int
jit_insn_set_param_ptr(jit_function_t func, jit_value_t value, jit_type_t type,
jit_nint offset)
{
jit_value_t offset_value, size_value;
switch(jit_type_remove_tags(type)->kind)
{
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
offset_value = jit_value_create_nint_constant(func, jit_type_nint, offset);
size_value = jit_value_create_nint_constant(func, jit_type_nint,
jit_type_get_size(type));
if(!offset_value || !size_value)
{
return 0;
}
return apply_ternary(func, JIT_OP_SET_PARAM_STRUCT, offset_value, value,
size_value);
default:
value = jit_insn_load_relative(func, value, 0, type);
if(!value)
{
return 0;
}
return jit_insn_set_param(func, value, offset);
}
}
int
jit_insn_push_return_area_ptr(jit_function_t func)
{
return create_noarg_note(func, JIT_OP_PUSH_RETURN_AREA_PTR);
}
int
jit_insn_pop_stack(jit_function_t func, jit_nint num_items)
{
jit_value_t num_value = jit_value_create_nint_constant(func, jit_type_nint, num_items);
return create_unary_note(func, JIT_OP_POP_STACK, num_value);
}
int
jit_insn_defer_pop_stack(jit_function_t func, jit_nint num_items)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
func->builder->deferred_items += num_items;
return 1;
}
int
jit_insn_flush_defer_pop(jit_function_t func, jit_nint num_items)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_nint current_items = func->builder->deferred_items;
if(current_items >= num_items && current_items > 0)
{
func->builder->deferred_items = 0;
return jit_insn_pop_stack(func, current_items);
}
return 1;
}
int
jit_insn_return(jit_function_t func, jit_value_t value)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
#if !defined(JIT_BACKEND_INTERP)
if(func->has_try)
{
jit_type_t type = jit_type_create_signature(jit_abi_cdecl, jit_type_void, 0, 0, 1);
if(!type)
{
return 0;
}
jit_insn_call_native(func, "_jit_unwind_pop_setjmp",
(void *) _jit_unwind_pop_setjmp, type,
0, 0, JIT_CALL_NOTHROW);
jit_type_free(type);
}
#endif
func->builder->ordinary_return = 1;
jit_type_t type = jit_type_get_return(func->signature);
type = jit_type_promote_int(jit_type_normalize(type));
if(!value || type == jit_type_void)
{
if(!create_noarg_note(func, JIT_OP_RETURN))
{
return 0;
}
}
else
{
value = jit_insn_convert(func, value, type, 0);
if(!value)
{
return 0;
}
jit_value_t return_ptr, value_addr, size_value;
switch(type->kind)
{
case JIT_TYPE_SBYTE:
case JIT_TYPE_UBYTE:
case JIT_TYPE_SHORT:
case JIT_TYPE_USHORT:
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
if(!create_unary_note(func, JIT_OP_RETURN_INT, value))
{
return 0;
}
break;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
if(!create_unary_note(func, JIT_OP_RETURN_LONG, value))
{
return 0;
}
break;
case JIT_TYPE_FLOAT32:
if(!create_unary_note(func, JIT_OP_RETURN_FLOAT32, value))
{
return 0;
}
break;
case JIT_TYPE_FLOAT64:
if(!create_unary_note(func, JIT_OP_RETURN_FLOAT64, value))
{
return 0;
}
break;
case JIT_TYPE_NFLOAT:
if(!create_unary_note(func, JIT_OP_RETURN_NFLOAT, value))
{
return 0;
}
break;
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
value_addr = jit_insn_address_of(func, value);
size_value = jit_value_create_nint_constant(func, jit_type_nint,
jit_type_get_size(type));
if(!value_addr || !size_value)
{
return 0;
}
return_ptr = jit_value_get_struct_pointer(func);
if(return_ptr)
{
if(!jit_insn_memcpy(func, return_ptr, value_addr, size_value))
{
return 0;
}
if(!create_noarg_note(func, JIT_OP_RETURN))
{
return 0;
}
}
else
{
if(!create_note(func, JIT_OP_RETURN_SMALL_STRUCT, value_addr,
size_value))
{
return 0;
}
}
break;
}
}
func->builder->current_block->ends_in_dead = 1;
return jit_insn_new_block(func);
}
int
jit_insn_return_ptr(jit_function_t func, jit_value_t value, jit_type_t type)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
#if !defined(JIT_BACKEND_INTERP)
if(func->has_try)
{
type = jit_type_create_signature(jit_abi_cdecl, jit_type_void, 0, 0, 1);
if(!type)
{
return 0;
}
jit_insn_call_native(func, "_jit_unwind_pop_setjmp",
(void *) _jit_unwind_pop_setjmp, type,
0, 0, JIT_CALL_NOTHROW);
jit_type_free(type);
}
#endif
func->builder->ordinary_return = 1;
value = jit_insn_convert(func, value, jit_type_void_ptr, 0);
if(!value)
{
return 0;
}
jit_value_t return_ptr, size_value;
switch(jit_type_remove_tags(type)->kind)
{
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
size_value = jit_value_create_nint_constant(func, jit_type_nint,
jit_type_get_size(type));
if(!size_value)
{
return 0;
}
return_ptr = jit_value_get_struct_pointer(func);
if(return_ptr)
{
if(!jit_insn_memcpy(func, return_ptr, value, size_value))
{
return 0;
}
if(!create_noarg_note(func, JIT_OP_RETURN))
{
return 0;
}
}
else
{
if(!create_note(func, JIT_OP_RETURN_SMALL_STRUCT, value, size_value))
{
return 0;
}
}
break;
default:
value = jit_insn_load_relative(func, value, 0, type);
if(!value)
{
return 0;
}
return jit_insn_return(func, value);
}
func->builder->current_block->ends_in_dead = 1;
return jit_insn_new_block(func);
}
int
jit_insn_default_return(jit_function_t func)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(jit_block_current_is_dead(func))
{
return 2;
}
return jit_insn_return(func, 0);
}
int
jit_insn_throw(jit_function_t func, jit_value_t value)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
func->builder->may_throw = 1;
func->builder->non_leaf = 1;
if(!create_unary_note(func, JIT_OP_THROW, value))
{
return 0;
}
func->builder->current_block->ends_in_dead = 1;
return jit_insn_new_block(func);
}
jit_value_t
jit_insn_get_call_stack(jit_function_t func)
{
jit_type_t type = jit_type_create_signature(jit_abi_cdecl, jit_type_void_ptr, 0, 0, 1);
if(!type)
{
return 0;
}
jit_value_t value
= jit_insn_call_native(func, "jit_exception_get_stack_trace",
(void *) jit_exception_get_stack_trace,
type, 0, 0, 0);
jit_type_free(type);
return value;
}
jit_value_t
jit_insn_thrown_exception(jit_function_t func)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!func->builder->thrown_exception)
{
func->builder->thrown_exception =
jit_value_create(func, jit_type_void_ptr);
}
return func->builder->thrown_exception;
}
static int
initialize_setjmp_block(jit_function_t func)
{
#if !defined(JIT_BACKEND_INTERP)
jit_label_t start_label = jit_label_undefined;
jit_label_t end_label = jit_label_undefined;
jit_label_t code_label = jit_label_undefined;
jit_label_t rethrow_label = jit_label_undefined;
jit_value_t args[2];
jit_value_t value;
if(func->builder->setjmp_value)
{
return 1;
}
func->builder->catcher_label = jit_label_undefined;
if(!jit_insn_label_tight(func, &start_label))
{
return 0;
}
jit_type_t type = jit_type_create_struct(0, 0, 1);
if(!type)
{
return 0;
}
jit_type_set_size_and_alignment(type, sizeof(jit_jmp_buf), JIT_BEST_ALIGNMENT);
func->builder->setjmp_value = jit_value_create(func, type);
if(!func->builder->setjmp_value)
{
jit_type_free(type);
return 0;
}
jit_type_free(type);
type = jit_type_void_ptr;
type = jit_type_create_signature(jit_abi_cdecl, jit_type_void, &type, 1, 1);
if(!type)
{
return 0;
}
args[0] = jit_insn_address_of(func, func->builder->setjmp_value);
if(!args[0])
{
return 0;
}
jit_insn_call_native(func, "_jit_unwind_push_setjmp",
(void *) _jit_unwind_push_setjmp, type,
args, 1, JIT_CALL_NOTHROW);
jit_type_free(type);
#if defined(HAVE___SIGSETJMP) || defined(HAVE_SIGSETJMP)
{
jit_type_t params[2];
params[0] = jit_type_void_ptr;
params[1] = jit_type_sys_int;
type = jit_type_create_signature(jit_abi_cdecl, jit_type_int, params, 2, 1);
if(!type)
{
return 0;
}
}
args[0] = jit_insn_address_of(func, func->builder->setjmp_value);
args[1] = jit_value_create_nint_constant(func, jit_type_sys_int, 1);
if(!args[0] || !args[1])
{
jit_type_free(type);
return 0;
}
#if defined(HAVE___SIGSETJMP)
value = jit_insn_call_native(func, "__sigsetjmp", (void *) __sigsetjmp,
type, args, 2, JIT_CALL_NOTHROW);
#else
value = jit_insn_call_native(func, "sigsetjmp", (void *) sigsetjmp,
type, args, 2, JIT_CALL_NOTHROW);
#endif
jit_type_free(type);
if(!value)
{
return 0;
}
#else
type = jit_type_void_ptr;
type = jit_type_create_signature(jit_abi_cdecl, jit_type_int, &type, 1, 1);
if(!type)
{
return 0;
}
args[0] = jit_insn_address_of(func, func->builder->setjmp_value);
if(!args[0])
{
jit_type_free(type);
return 0;
}
#if defined(HAVE__SETJMP)
value = jit_insn_call_native(func, "_setjmp", (void *) _setjmp,
type, args, 1, JIT_CALL_NOTHROW);
#else
value = jit_insn_call_native(func, "setjmp", (void *) setjmp,
type, args, 1, JIT_CALL_NOTHROW);
#endif
jit_type_free(type);
if(!value)
{
return 0;
}
#endif
if(!jit_insn_branch_if_not(func, value, &code_label))
{
return 0;
}
func->builder->thrown_pc = jit_value_create(func, jit_type_void_ptr);
if(func->builder->thrown_pc == 0)
{
return 0;
}
value = jit_insn_address_of(func, func->builder->setjmp_value);
if(!value)
{
return 0;
}
value = jit_insn_load_relative(func, value, jit_jmp_catch_pc_offset, jit_type_void_ptr);
if(!value)
{
return 0;
}
if(!jit_insn_store(func, func->builder->thrown_pc, value))
{
return 0;
}
if(!jit_insn_branch_if_not(func, value, &rethrow_label))
{
return 0;
}
jit_value_t null = jit_value_create_nint_constant(func, jit_type_void_ptr, 0);
value = jit_insn_address_of(func, func->builder->setjmp_value);
if(!null || !value)
{
return 0;
}
if(!jit_insn_store_relative(func, value, jit_jmp_catch_pc_offset, null))
{
return 0;
}
if(!jit_insn_branch(func, &func->builder->catcher_label))
{
return 0;
}
if(!jit_insn_label_tight(func, &rethrow_label))
{
return 0;
}
type = jit_type_create_signature(jit_abi_cdecl, jit_type_void, 0, 0, 1);
if(!type)
{
return 0;
}
jit_insn_call_native(func, "_jit_unwind_pop_and_rethrow",
(void *) _jit_unwind_pop_and_rethrow, type, 0, 0,
JIT_CALL_NOTHROW | JIT_CALL_NORETURN);
jit_type_free(type);
if(!jit_insn_label_tight(func, &code_label))
{
return 0;
}
if(!jit_insn_label(func, &end_label))
{
return 0;
}
return jit_insn_move_blocks_to_start(func, start_label, end_label);
#else
func->builder->catcher_label = jit_label_undefined;
return 1;
#endif
}
int
jit_insn_uses_catcher(jit_function_t func)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(func->has_try)
{
return 1;
}
func->has_try = 1;
func->builder->may_throw = 1;
func->builder->non_leaf = 1;
return initialize_setjmp_block(func);
}
jit_value_t
jit_insn_start_catcher(jit_function_t func)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!jit_insn_label_tight(func, &func->builder->catcher_label))
{
return 0;
}
jit_value_t value = jit_insn_thrown_exception(func);
if(!value)
{
return 0;
}
#if defined(JIT_BACKEND_INTERP)
if(!jit_insn_incoming_reg(func, value, 0))
{
return 0;
}
#else
jit_type_t type = jit_type_create_signature(jit_abi_cdecl, jit_type_void_ptr, 0, 0, 1);
if(!type)
{
return 0;
}
jit_value_t last_exception
= jit_insn_call_native(func, "jit_exception_get_last",
(void *) jit_exception_get_last,
type, 0, 0, JIT_CALL_NOTHROW);
jit_insn_store(func, value, last_exception);
jit_type_free(type);
#endif
return value;
}
int
jit_insn_branch_if_pc_not_in_range(jit_function_t func, jit_label_t start_label,
jit_label_t end_label, jit_label_t *label)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!func->has_try)
{
return 0;
}
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
#if defined(JIT_BACKEND_INTERP)
jit_value_t value1 = create_dest_note(func, JIT_OP_LOAD_EXCEPTION_PC, jit_type_void_ptr);
#else
jit_value_t value1 = func->builder->thrown_pc;
#endif
if(!value1)
{
return 0;
}
jit_value_t value2 = jit_insn_address_of_label(func, &start_label);
if(!value2)
{
return 0;
}
value2 = jit_insn_lt(func, value1, value2);
if(!value2 || !jit_insn_branch_if(func, value2, label))
{
return 0;
}
value2 = jit_insn_address_of_label(func, &end_label);
if(!value2)
{
return 0;
}
value2 = jit_insn_ge(func, value1, value2);
if(!value2 || !jit_insn_branch_if(func, value2, label))
{
return 0;
}
return 1;
}
int
jit_insn_rethrow_unhandled(jit_function_t func)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_value_t value = jit_insn_thrown_exception(func);
if(!value)
{
return 0;
}
#if defined(JIT_BACKEND_INTERP)
if(!create_unary_note(func, JIT_OP_RETHROW, value))
{
return 0;
}
#else
jit_type_t type = jit_type_create_signature(jit_abi_cdecl, jit_type_void, 0, 0, 1);
if(!type)
{
return 0;
}
jit_insn_call_native(func, "_jit_unwind_pop_setjmp",
(void *) _jit_unwind_pop_setjmp, type, 0, 0,
JIT_CALL_NOTHROW);
jit_type_free(type);
type = jit_type_void_ptr;
type = jit_type_create_signature(jit_abi_cdecl, jit_type_void, &type, 1, 1);
if(!type)
{
return 0;
}
jit_insn_call_native(func, "jit_exception_throw",
(void *) jit_exception_throw, type, &value, 1,
JIT_CALL_NOTHROW | JIT_CALL_NORETURN);
jit_type_free(type);
#endif
func->builder->current_block->ends_in_dead = 1;
return jit_insn_new_block(func);
}
int
jit_insn_start_finally(jit_function_t func, jit_label_t *finally_label)
{
if(!jit_insn_label_tight(func, finally_label))
{
return 0;
}
return create_noarg_note(func, JIT_OP_ENTER_FINALLY);
}
int
jit_insn_return_from_finally(jit_function_t func)
{
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
if(!create_noarg_note(func, JIT_OP_LEAVE_FINALLY))
{
return 0;
}
func->builder->current_block->ends_in_dead = 1;
return jit_insn_new_block(func);
}
int
jit_insn_call_finally(jit_function_t func, jit_label_t *finally_label)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
if(*finally_label == jit_label_undefined)
{
*finally_label = func->builder->next_label++;
}
func->builder->non_leaf = 1;
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) JIT_OP_CALL_FINALLY;
insn->flags = JIT_INSN_DEST_IS_LABEL;
insn->dest = (jit_value_t) *finally_label;
return jit_insn_new_block(func);
}
jit_value_t
jit_insn_start_filter(jit_function_t func, jit_label_t *label, jit_type_t type)
{
if(!jit_insn_label_tight(func, label))
{
return 0;
}
return create_dest_note(func, JIT_OP_ENTER_FILTER, type);
}
int
jit_insn_return_from_filter(jit_function_t func, jit_value_t value)
{
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
if(!create_unary_note(func, JIT_OP_LEAVE_FILTER, value))
{
return 0;
}
func->builder->current_block->ends_in_dead = 1;
return jit_insn_new_block(func);
}
jit_value_t
jit_insn_call_filter(jit_function_t func, jit_label_t *label,
jit_value_t value, jit_type_t type)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
if(*label == jit_label_undefined)
{
*label = func->builder->next_label++;
}
func->builder->non_leaf = 1;
jit_insn_t insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
return 0;
}
insn->opcode = (short) JIT_OP_CALL_FILTER;
insn->flags = JIT_INSN_DEST_IS_LABEL;
insn->dest = (jit_value_t) *label;
insn->value1 = value;
jit_value_ref(func, value);
if(!jit_insn_new_block(func))
{
return 0;
}
return create_dest_note(func, JIT_OP_CALL_FILTER_RETURN, type);
}
int
jit_insn_memcpy(jit_function_t func, jit_value_t dest, jit_value_t src, jit_value_t size)
{
size = jit_insn_convert(func, size, jit_type_nint, 0);
if(!size)
{
return 0;
}
return apply_ternary(func, JIT_OP_MEMCPY, dest, src, size);
}
int
jit_insn_memmove(jit_function_t func, jit_value_t dest, jit_value_t src, jit_value_t size)
{
size = jit_insn_convert(func, size, jit_type_nint, 0);
if(!size)
{
return 0;
}
return apply_ternary(func, JIT_OP_MEMMOVE, dest, src, size);
}
int
jit_insn_memset(jit_function_t func, jit_value_t dest, jit_value_t value, jit_value_t size)
{
value = jit_insn_convert(func, value, jit_type_int, 0);
size = jit_insn_convert(func, size, jit_type_nint, 0);
if(!value || !size)
{
return 0;
}
return apply_ternary(func, JIT_OP_MEMSET, dest, value, size);
}
jit_value_t
jit_insn_alloca(jit_function_t func, jit_value_t size)
{
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
size = jit_insn_convert(func, size, jit_type_nuint, 0);
jit_value_t addon = jit_value_create_nint_constant(
func, jit_type_nuint, JIT_BEST_ALIGNMENT - 1);
jit_value_t mask = jit_value_create_nint_constant(
func, jit_type_nuint, ~((jit_nint) (JIT_BEST_ALIGNMENT - 1)));
if(!size || !addon || !mask)
{
return 0;
}
size = jit_insn_add(func, size, addon);
if(!size)
{
return 0;
}
size = jit_insn_and(func, size, mask);
if(!size)
{
return 0;
}
return apply_unary(func, JIT_OP_ALLOCA, size, jit_type_void_ptr);
}
int
jit_insn_move_blocks_to_end(jit_function_t func, jit_label_t from_label,
jit_label_t to_label)
{
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
jit_block_t first = jit_block_from_label(func, from_label);
if(!first)
{
return 0;
}
jit_block_t last = jit_block_from_label(func, to_label);
if(!last)
{
return 0;
}
jit_block_t block;
for(block = first->next; block != last; block = block->next)
{
if(!block)
{
return 0;
}
}
block = last->prev;
_jit_block_detach(first, block);
_jit_block_attach_before(func->builder->exit_block, first, block);
func->builder->current_block = block;
return jit_insn_new_block(func);
}
int
jit_insn_move_blocks_to_start(jit_function_t func, jit_label_t from_label, jit_label_t to_label)
{
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
jit_block_t first = jit_block_from_label(func, from_label);
if(!first)
{
return 0;
}
jit_block_t last = jit_block_from_label(func, to_label);
if(!last)
{
return 0;
}
jit_block_t init = func->builder->init_block;
jit_block_t block;
for(block = init->next; block != first; block = block->next)
{
if(!block)
{
return 0;
}
}
for(block = first->next; block != last; block = block->next)
{
if(!block)
{
return 0;
}
}
block = last->prev;
func->builder->init_block = block;
if(init->next != first)
{
_jit_block_detach(first, block);
_jit_block_attach_after(init, first, block);
}
return 1;
}
int
jit_insn_mark_offset(jit_function_t func, jit_int offset)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
jit_value_t value = jit_value_create_nint_constant(func, jit_type_int, offset);
if(!value)
{
return 0;
}
jit_block_t block = func->builder->current_block;
jit_insn_t last = _jit_block_get_last(block);
if(last && last->opcode == JIT_OP_MARK_OFFSET)
{
last->value1 = value;
return 1;
}
return create_unary_note(func, JIT_OP_MARK_OFFSET, value);
}
int
jit_insn_mark_breakpoint_variable(jit_function_t func, jit_value_t data1, jit_value_t data2)
{
#if defined(JIT_BACKEND_INTERP)
if(!jit_insn_new_block(func))
{
return 0;
}
return create_note(func, JIT_OP_MARK_BREAKPOINT, data1, data2);
#else
jit_type_t params[3];
jit_type_t signature;
jit_value_t values[3];
params[0] = jit_type_void_ptr;
params[1] = jit_type_nint;
params[2] = jit_type_nint;
signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void, params, 3, 0);
if(!signature)
{
return 0;
}
values[0] = jit_value_create_nint_constant(func, jit_type_void_ptr, (jit_nint) func);
if(!values[0])
{
jit_type_free(signature);
return 0;
}
values[1] = data1;
values[2] = data2;
jit_insn_call_native(func, "_jit_debugger_hook", (void *) _jit_debugger_hook,
signature, values, 3, JIT_CALL_NOTHROW);
jit_type_free(signature);
return 1;
#endif
}
int
jit_insn_mark_breakpoint(jit_function_t func, jit_nint data1, jit_nint data2)
{
jit_value_t value1;
jit_value_t value2;
value1 = jit_value_create_nint_constant(func, jit_type_nint, data1);
value2 = jit_value_create_nint_constant(func, jit_type_nint, data2);
if(!value1 || !value2)
{
return 0;
}
return jit_insn_mark_breakpoint_variable(func, value1, value2);
}
void
jit_insn_iter_init(jit_insn_iter_t *iter, jit_block_t block)
{
iter->block = block;
iter->posn = 0;
}
void
jit_insn_iter_init_last(jit_insn_iter_t *iter, jit_block_t block)
{
iter->block = block;
iter->posn = block->num_insns;
}
jit_insn_t
jit_insn_iter_next(jit_insn_iter_t *iter)
{
if(iter->posn < iter->block->num_insns)
{
return &iter->block->insns[iter->posn++];
}
else
{
return 0;
}
}
jit_insn_t
jit_insn_iter_previous(jit_insn_iter_t *iter)
{
if(iter->posn > 0)
{
return &iter->block->insns[--iter->posn];
}
else
{
return 0;
}
}