mirror of https://github.com/ademakov/libjit
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
833 lines
17 KiB
833 lines
17 KiB
/*
|
|
* jit-rules.c - Rules that define the characteristics of the back-end.
|
|
*
|
|
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "jit-internal.h"
|
|
#include "jit-rules.h"
|
|
|
|
/*
|
|
* The information blocks for all registers in the system.
|
|
*/
|
|
jit_reginfo_t const _jit_reg_info[JIT_NUM_REGS] = {JIT_REG_INFO};
|
|
|
|
#ifdef JIT_CDECL_WORD_REG_PARAMS
|
|
|
|
/*
|
|
* List of registers to use for simple parameter passing.
|
|
*/
|
|
static int const cdecl_word_regs[] = JIT_CDECL_WORD_REG_PARAMS;
|
|
#ifdef JIT_FASTCALL_WORD_REG_PARAMS
|
|
static int const fastcall_word_regs[] = JIT_FASTCALL_WORD_REG_PARAMS;
|
|
#endif
|
|
|
|
/*
|
|
* Structure that is used to help with parameter passing.
|
|
*/
|
|
typedef struct
|
|
{
|
|
jit_nint offset;
|
|
unsigned int index;
|
|
unsigned int max_regs;
|
|
const int *word_regs;
|
|
jit_value_t word_values[JIT_MAX_WORD_REG_PARAMS];
|
|
|
|
} jit_param_passing_t;
|
|
|
|
/*
|
|
* Round a size up to a multiple of the stack word size.
|
|
*/
|
|
#define ROUND_STACK(size) \
|
|
(((size) + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1))
|
|
#define STACK_WORDS(size) \
|
|
(((size) + (sizeof(void *) - 1)) / sizeof(void *))
|
|
|
|
/*
|
|
* Allocate a word register or incoming frame position to a value.
|
|
*/
|
|
static int alloc_incoming_word
|
|
(jit_function_t func, jit_param_passing_t *passing,
|
|
jit_value_t value, int extra_offset)
|
|
{
|
|
int reg;
|
|
reg = passing->word_regs[passing->index];
|
|
if(reg != -1 && passing->word_values[passing->index] != 0)
|
|
{
|
|
/* The value was already forced out previously, so just copy it */
|
|
if(!jit_insn_store(func, value, passing->word_values[passing->index]))
|
|
{
|
|
return 0;
|
|
}
|
|
++(passing->index);
|
|
}
|
|
else if(reg != -1)
|
|
{
|
|
if(!jit_insn_incoming_reg(func, value, reg))
|
|
{
|
|
return 0;
|
|
}
|
|
++(passing->index);
|
|
}
|
|
else
|
|
{
|
|
if(!jit_insn_incoming_frame_posn
|
|
(func, value, passing->offset + extra_offset))
|
|
{
|
|
return 0;
|
|
}
|
|
passing->offset += sizeof(void *);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Force the remaining word registers out into temporary values,
|
|
* to protect them from being accidentally overwritten by the code
|
|
* that deals with multi-word parameters.
|
|
*/
|
|
static int force_remaining_out
|
|
(jit_function_t func, jit_param_passing_t *passing)
|
|
{
|
|
unsigned int index = passing->index;
|
|
jit_value_t value;
|
|
while(index < passing->max_regs && passing->word_regs[index] != -1)
|
|
{
|
|
if(passing->word_values[index] != 0)
|
|
{
|
|
/* We've already done this before */
|
|
return 1;
|
|
}
|
|
value = jit_value_create(func, jit_type_void_ptr);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_insn_incoming_reg(func, value, passing->word_regs[index]))
|
|
{
|
|
return 0;
|
|
}
|
|
passing->word_values[index] = value;
|
|
++index;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _jit_create_entry_insns(jit_function_t func)
|
|
{
|
|
jit_type_t signature = func->signature;
|
|
jit_type_t type;
|
|
jit_value_t value;
|
|
jit_value_t temp;
|
|
jit_value_t addr_of;
|
|
unsigned int num_params;
|
|
unsigned int param;
|
|
unsigned int size;
|
|
jit_param_passing_t passing;
|
|
jit_nint partial_offset;
|
|
|
|
/* Reset the local variable frame size for this function */
|
|
func->builder->frame_size = JIT_INITIAL_FRAME_SIZE;
|
|
|
|
/* Initialize the parameter passing information block */
|
|
passing.offset = JIT_INITIAL_STACK_OFFSET;
|
|
passing.index = 0;
|
|
#ifdef JIT_FASTCALL_WORD_REG_PARAMS
|
|
if(jit_type_get_abi(signature) == jit_abi_fastcall)
|
|
{
|
|
passing.word_regs = fastcall_word_regs;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
passing.word_regs = cdecl_word_regs;
|
|
}
|
|
for(size = 0; size < JIT_MAX_WORD_REG_PARAMS; ++size)
|
|
{
|
|
passing.word_values[size] = 0;
|
|
}
|
|
|
|
/* If the function is nested, then we need an extra parameter
|
|
to pass the pointer to the parent's local variable frame */
|
|
if(func->nested_parent)
|
|
{
|
|
value = jit_value_create(func, jit_type_void_ptr);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
func->builder->parent_frame = value;
|
|
if(!alloc_incoming_word(func, &passing, value, 0))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Allocate the structure return pointer */
|
|
value = jit_value_get_struct_pointer(func);
|
|
if(value)
|
|
{
|
|
if(!alloc_incoming_word(func, &passing, value, 0))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Determine the maximum number of registers that may be needed
|
|
to pass the function's parameters */
|
|
num_params = jit_type_num_params(signature);
|
|
passing.max_regs = passing.index;
|
|
for(param = 0; param < num_params; ++param)
|
|
{
|
|
value = jit_value_get_param(func, param);
|
|
if(value)
|
|
{
|
|
size = STACK_WORDS(jit_type_get_size(jit_value_get_type(value)));
|
|
passing.max_regs += size;
|
|
}
|
|
}
|
|
|
|
/* Allocate the parameter offsets */
|
|
for(param = 0; param < num_params; ++param)
|
|
{
|
|
value = jit_value_get_param(func, param);
|
|
if(!value)
|
|
{
|
|
continue;
|
|
}
|
|
type = jit_type_remove_tags(jit_value_get_type(value));
|
|
switch(type->kind)
|
|
{
|
|
case JIT_TYPE_SBYTE:
|
|
case JIT_TYPE_UBYTE:
|
|
{
|
|
if(!alloc_incoming_word
|
|
(func, &passing, value, _jit_nint_lowest_byte()))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_SHORT:
|
|
case JIT_TYPE_USHORT:
|
|
{
|
|
if(!alloc_incoming_word
|
|
(func, &passing, value, _jit_nint_lowest_short()))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_INT:
|
|
case JIT_TYPE_UINT:
|
|
{
|
|
if(!alloc_incoming_word
|
|
(func, &passing, value, _jit_nint_lowest_int()))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NINT:
|
|
case JIT_TYPE_NUINT:
|
|
case JIT_TYPE_SIGNATURE:
|
|
case JIT_TYPE_PTR:
|
|
{
|
|
if(!alloc_incoming_word(func, &passing, value, 0))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
case JIT_TYPE_ULONG:
|
|
#ifdef JIT_NATIVE_INT64
|
|
{
|
|
if(!alloc_incoming_word(func, &passing, value, 0))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
/* Fall through on 32-bit platforms */
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
case JIT_TYPE_FLOAT64:
|
|
case JIT_TYPE_NFLOAT:
|
|
case JIT_TYPE_STRUCT:
|
|
case JIT_TYPE_UNION:
|
|
{
|
|
/* Force the remaining registers out into temporary copies */
|
|
if(!force_remaining_out(func, &passing))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* Determine how many words that we need to copy */
|
|
size = STACK_WORDS(jit_type_get_size(type));
|
|
|
|
/* If there are no registers left, then alloc on the stack */
|
|
if(passing.word_regs[passing.index] == -1)
|
|
{
|
|
if(!jit_insn_incoming_frame_posn
|
|
(func, value, passing.offset))
|
|
{
|
|
return 0;
|
|
}
|
|
passing.offset += size * sizeof(void *);
|
|
break;
|
|
}
|
|
|
|
/* Copy the register components across */
|
|
partial_offset = 0;
|
|
addr_of = jit_insn_address_of(func, value);
|
|
if(!addr_of)
|
|
{
|
|
return 0;
|
|
}
|
|
while(size > 0 && passing.word_regs[passing.index] != -1)
|
|
{
|
|
temp = passing.word_values[passing.index];
|
|
++(passing.index);
|
|
if(!jit_insn_store_relative
|
|
(func, addr_of, partial_offset, temp))
|
|
{
|
|
return 0;
|
|
}
|
|
partial_offset += sizeof(void *);
|
|
--size;
|
|
}
|
|
|
|
/* Copy the stack components across */
|
|
while(size > 0)
|
|
{
|
|
temp = jit_value_create(func, jit_type_void_ptr);
|
|
if(!temp)
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_insn_incoming_frame_posn
|
|
(func, temp, passing.offset))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_insn_store_relative
|
|
(func, addr_of, partial_offset, temp))
|
|
{
|
|
return 0;
|
|
}
|
|
passing.offset += sizeof(void *);
|
|
partial_offset += sizeof(void *);
|
|
--size;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Record that we need an outgoing register or stack slot for a word value.
|
|
*/
|
|
static void need_outgoing_word(jit_param_passing_t *passing)
|
|
{
|
|
if(passing->word_regs[passing->index] != -1)
|
|
{
|
|
++(passing->index);
|
|
}
|
|
else
|
|
{
|
|
passing->offset += sizeof(void *);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Record that we need an outgoing register, containing a particular value.
|
|
*/
|
|
static void need_outgoing_value
|
|
(jit_param_passing_t *passing, jit_value_t value)
|
|
{
|
|
passing->word_values[passing->index] = value;
|
|
++(passing->index);
|
|
}
|
|
|
|
/*
|
|
* Count the number of registers that are left for parameter passing.
|
|
*/
|
|
static jit_nint count_regs_left(jit_param_passing_t *passing)
|
|
{
|
|
int left = 0;
|
|
unsigned int index = passing->index;
|
|
while(passing->word_regs[index] != -1)
|
|
{
|
|
++left;
|
|
++index;
|
|
}
|
|
return left;
|
|
}
|
|
|
|
/*
|
|
* Determine if a type corresponds to a structure or union.
|
|
*/
|
|
static int is_struct_or_union(jit_type_t type)
|
|
{
|
|
type = jit_type_normalize(type);
|
|
if(type)
|
|
{
|
|
if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Push a parameter onto the stack.
|
|
*/
|
|
static int push_param
|
|
(jit_function_t func, jit_param_passing_t *passing,
|
|
jit_value_t value, jit_type_t type)
|
|
{
|
|
jit_nint size = (jit_nint)(jit_type_get_size(value->type));
|
|
passing->offset -= ROUND_STACK(size);
|
|
if(is_struct_or_union(type) && !is_struct_or_union(value->type))
|
|
{
|
|
#ifdef JIT_USE_PARAM_AREA
|
|
/* Copy the value into the outgoing parameter area, by pointer */
|
|
if(!jit_insn_set_param_ptr(func, value, type, passing->offset))
|
|
{
|
|
return 0;
|
|
}
|
|
#else
|
|
/* Push the parameter value onto the stack, by pointer */
|
|
if(!jit_insn_push_ptr(func, value, type))
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef JIT_USE_PARAM_AREA
|
|
/* Copy the value into the outgoing parameter area */
|
|
if(!jit_insn_set_param(func, value, passing->offset))
|
|
{
|
|
return 0;
|
|
}
|
|
#else
|
|
/* Push the parameter value onto the stack */
|
|
if(!jit_insn_push(func, value))
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Allocate an outgoing word register to a value.
|
|
*/
|
|
static int alloc_outgoing_word
|
|
(jit_function_t func, jit_param_passing_t *passing, jit_value_t value)
|
|
{
|
|
int reg;
|
|
--(passing->index);
|
|
reg = passing->word_regs[passing->index];
|
|
if(passing->word_values[passing->index] != 0)
|
|
{
|
|
/* We copied the value previously, so use the copy instead */
|
|
value = passing->word_values[passing->index];
|
|
}
|
|
if(!jit_insn_outgoing_reg(func, value, reg))
|
|
{
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _jit_create_call_setup_insns
|
|
(jit_function_t func, jit_type_t signature,
|
|
jit_value_t *args, unsigned int num_args,
|
|
int is_nested, int nesting_level, jit_value_t *struct_return, int flags)
|
|
{
|
|
jit_type_t type;
|
|
jit_value_t value;
|
|
jit_nint size;
|
|
jit_nint regs_left;
|
|
jit_nint rounded_size;
|
|
jit_nint partial_offset;
|
|
jit_param_passing_t passing;
|
|
jit_value_t return_ptr;
|
|
jit_value_t partial;
|
|
unsigned int param;
|
|
|
|
/* Initialize the parameter passing information block */
|
|
passing.offset = 0;
|
|
passing.index = 0;
|
|
#ifdef JIT_FASTCALL_WORD_REG_PARAMS
|
|
if(jit_type_get_abi(signature) == jit_abi_fastcall)
|
|
{
|
|
passing.word_regs = fastcall_word_regs;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
passing.word_regs = cdecl_word_regs;
|
|
}
|
|
for(size = 0; size < JIT_MAX_WORD_REG_PARAMS; ++size)
|
|
{
|
|
passing.word_values[size] = 0;
|
|
}
|
|
|
|
/* Determine how many parameters are going to end up in word registers,
|
|
and compute the largest stack size needed to pass stack parameters */
|
|
if(is_nested)
|
|
{
|
|
need_outgoing_word(&passing);
|
|
}
|
|
type = jit_type_get_return(signature);
|
|
if(jit_type_return_via_pointer(type))
|
|
{
|
|
value = jit_value_create(func, type);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
*struct_return = value;
|
|
return_ptr = jit_insn_address_of(func, value);
|
|
if(!return_ptr)
|
|
{
|
|
return 0;
|
|
}
|
|
need_outgoing_word(&passing);
|
|
}
|
|
else
|
|
{
|
|
*struct_return = 0;
|
|
return_ptr = 0;
|
|
}
|
|
partial = 0;
|
|
for(param = 0; param < num_args; ++param)
|
|
{
|
|
type = jit_type_get_param(signature, param);
|
|
size = STACK_WORDS(jit_type_get_size(type));
|
|
if(size <= 1)
|
|
{
|
|
/* Allocate a word register or stack position */
|
|
need_outgoing_word(&passing);
|
|
}
|
|
else
|
|
{
|
|
regs_left = count_regs_left(&passing);
|
|
if(regs_left > 0)
|
|
{
|
|
/* May be partly in registers and partly on the stack */
|
|
if(is_struct_or_union(type) &&
|
|
!is_struct_or_union(jit_value_get_type(args[param])))
|
|
{
|
|
/* Passing a structure by pointer */
|
|
partial = args[param];
|
|
}
|
|
else if(jit_value_is_constant(args[param]))
|
|
{
|
|
if(size <= regs_left)
|
|
{
|
|
/* We can split the constant, without a temporary */
|
|
partial_offset = 0;
|
|
while(size > 0)
|
|
{
|
|
value = jit_value_create_nint_constant
|
|
(func, jit_type_void_ptr,
|
|
*((jit_nint *)(args[param]->address +
|
|
partial_offset)));
|
|
need_outgoing_value(&passing, value);
|
|
partial_offset += sizeof(void *);
|
|
--size;
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
/* Copy the constant into a temporary local variable */
|
|
partial = jit_value_create(func, type);
|
|
if(!partial)
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_insn_store(func, partial, args[param]))
|
|
{
|
|
return 0;
|
|
}
|
|
partial = jit_insn_address_of(func, partial);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Get the address of this parameter */
|
|
partial = jit_insn_address_of(func, args[param]);
|
|
}
|
|
if(!partial)
|
|
{
|
|
return 0;
|
|
}
|
|
partial_offset = 0;
|
|
while(size > 0 && regs_left > 0)
|
|
{
|
|
value = jit_insn_load_relative
|
|
(func, partial, partial_offset, jit_type_void_ptr);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
need_outgoing_value(&passing, value);
|
|
--size;
|
|
--regs_left;
|
|
partial_offset += sizeof(void *);
|
|
}
|
|
passing.offset += size * sizeof(void *);
|
|
}
|
|
else
|
|
{
|
|
/* Pass this parameter completely on the stack */
|
|
passing.offset += size * sizeof(void *);
|
|
}
|
|
}
|
|
}
|
|
#ifdef JIT_USE_PARAM_AREA
|
|
if(passing.offset > func->builder->param_area_size)
|
|
{
|
|
func->builder->param_area_size = passing.offset;
|
|
}
|
|
#else
|
|
/* Flush deferred stack pops from previous calls if too many
|
|
parameters have collected up on the stack since last time */
|
|
if(!jit_insn_flush_defer_pop(func, 32 - passing.offset))
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* Move all of the parameters into their final locations */
|
|
param = num_args;
|
|
while(param > 0)
|
|
{
|
|
--param;
|
|
type = jit_type_get_param(signature, param);
|
|
size = (jit_nint)(jit_type_get_size(type));
|
|
rounded_size = ROUND_STACK(size);
|
|
size = STACK_WORDS(size);
|
|
if(rounded_size <= passing.offset)
|
|
{
|
|
/* This parameter is completely on the stack */
|
|
if(!push_param(func, &passing, args[param], type))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else if(passing.offset > 0)
|
|
{
|
|
/* This parameter is split between the stack and registers */
|
|
while(passing.offset > 0)
|
|
{
|
|
rounded_size -= sizeof(void *);
|
|
value = jit_insn_load_relative
|
|
(func, partial, rounded_size, jit_type_void_ptr);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
if(!push_param(func, &passing, value, jit_type_void_ptr))
|
|
{
|
|
return 0;
|
|
}
|
|
--size;
|
|
}
|
|
while(size > 0)
|
|
{
|
|
if(!alloc_outgoing_word(func, &passing, 0))
|
|
{
|
|
return 0;
|
|
}
|
|
--size;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* This parameter is completely in registers. If the parameter
|
|
occupies multiple registers, then it has already been split */
|
|
while(size > 0)
|
|
{
|
|
if(!alloc_outgoing_word(func, &passing, args[param]))
|
|
{
|
|
return 0;
|
|
}
|
|
--size;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Add the structure return pointer if required */
|
|
if(return_ptr)
|
|
{
|
|
if(passing.index > 0)
|
|
{
|
|
if(!alloc_outgoing_word(func, &passing, return_ptr))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!push_param
|
|
(func, &passing, return_ptr, jit_type_void_ptr))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Add nested scope information if required */
|
|
if(is_nested)
|
|
{
|
|
if(passing.index > 0)
|
|
{
|
|
--(passing.index);
|
|
if(!jit_insn_setup_for_nested
|
|
(func, nesting_level, passing.word_regs[passing.index]))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!jit_insn_setup_for_nested(func, nesting_level, -1))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* The call is ready to proceed */
|
|
return 1;
|
|
}
|
|
|
|
#endif /* JIT_CDECL_WORD_REG_PARAMS */
|
|
|
|
int _jit_int_lowest_byte(void)
|
|
{
|
|
union
|
|
{
|
|
unsigned char bytes[4];
|
|
jit_int value;
|
|
} volatile un;
|
|
int posn;
|
|
un.value = (jit_int)0x01020304;
|
|
posn = 0;
|
|
while(un.bytes[posn] != 0x04)
|
|
{
|
|
++posn;
|
|
}
|
|
return posn;
|
|
}
|
|
|
|
int _jit_int_lowest_short(void)
|
|
{
|
|
union
|
|
{
|
|
unsigned char bytes[4];
|
|
jit_int value;
|
|
} volatile un;
|
|
int posn;
|
|
un.value = (jit_int)0x01020304;
|
|
posn = 0;
|
|
while(un.bytes[posn] != 0x03 && un.bytes[posn] != 0x04)
|
|
{
|
|
++posn;
|
|
}
|
|
return posn;
|
|
}
|
|
|
|
int _jit_nint_lowest_byte(void)
|
|
{
|
|
#ifdef JIT_NATIVE_INT32
|
|
return _jit_int_lowest_byte();
|
|
#else
|
|
union
|
|
{
|
|
unsigned char bytes[8];
|
|
jit_long value;
|
|
} volatile un;
|
|
int posn;
|
|
un.value = (jit_long)0x0102030405060708;
|
|
posn = 0;
|
|
while(un.bytes[posn] != 0x08)
|
|
{
|
|
++posn;
|
|
}
|
|
return posn;
|
|
#endif
|
|
}
|
|
|
|
int _jit_nint_lowest_short(void)
|
|
{
|
|
#ifdef JIT_NATIVE_INT32
|
|
return _jit_int_lowest_short();
|
|
#else
|
|
union
|
|
{
|
|
unsigned char bytes[8];
|
|
jit_long value;
|
|
} volatile un;
|
|
int posn;
|
|
un.value = (jit_long)0x0102030405060708;
|
|
posn = 0;
|
|
while(un.bytes[posn] != 0x07 && un.bytes[posn] != 0x08)
|
|
{
|
|
++posn;
|
|
}
|
|
return posn;
|
|
#endif
|
|
}
|
|
|
|
int _jit_nint_lowest_int(void)
|
|
{
|
|
#ifdef JIT_NATIVE_INT32
|
|
return 0;
|
|
#else
|
|
union
|
|
{
|
|
unsigned char bytes[8];
|
|
jit_long value;
|
|
} volatile un;
|
|
int posn;
|
|
un.value = (jit_long)0x0102030405060708;
|
|
posn = 0;
|
|
while(un.bytes[posn] <= 0x04)
|
|
{
|
|
++posn;
|
|
}
|
|
return posn;
|
|
#endif
|
|
}
|
|
|