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.
2128 lines
47 KiB
2128 lines
47 KiB
/*
|
|
* jit-value.c - Functions for manipulating temporary values.
|
|
*
|
|
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
|
|
*
|
|
* This file is part of the libjit library.
|
|
*
|
|
* The libjit library is free software: you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation, either version 2.1 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* The libjit library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with the libjit library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "jit-internal.h"
|
|
#include "jit-rules.h"
|
|
|
|
/*@
|
|
|
|
@cindex jit-value.h
|
|
|
|
Values form the backbone of the storage system in @code{libjit}.
|
|
Every value in the system, be it a constant, a local variable,
|
|
or a temporary result, is represented by an object of type
|
|
@code{jit_value_t}. The JIT then allocates registers or memory
|
|
locations to the values as appropriate.
|
|
|
|
We will demonstrate how to use values with a simple example of
|
|
adding two local variables together and putting the result into a
|
|
third local variable. First, we allocate storage for the
|
|
three local variables:
|
|
|
|
@example
|
|
value1 = jit_value_create(func, jit_type_int);
|
|
value2 = jit_value_create(func, jit_type_int);
|
|
value3 = jit_value_create(func, jit_type_int);
|
|
@end example
|
|
|
|
Here, @code{func} is the function that we are building. To add
|
|
@code{value1} and @code{value2} and put the result into @code{value3},
|
|
we use the following code:
|
|
|
|
@example
|
|
temp = jit_insn_add(func, value1, value2);
|
|
jit_insn_store(func, value3, temp);
|
|
@end example
|
|
|
|
The @code{jit_insn_add} function allocates a temporary value
|
|
(@code{temp}) and places the result of the addition into it.
|
|
The @code{jit_insn_store} function then stores the temporary
|
|
result into @code{value3}.
|
|
|
|
You might be tempted to think that the above code is inefficient.
|
|
Why do we copy the result into a temporary variable first?
|
|
Why not put the result directly to @code{value3}?
|
|
|
|
Behind the scenes, the JIT will typically optimize @code{temp} away,
|
|
resulting in the final code that you expect (i.e. @code{value3 = value1 +
|
|
value2}). It is simply easier to use @code{libjit} if all results
|
|
end up in temporary variables first, so that's what we do.
|
|
|
|
Using temporary values, it is very easy to convert stack machine
|
|
bytecodes into JIT instructions. Consider the following Java
|
|
Virtual Machine bytecode (representing @code{value4 = value1 * value2 +
|
|
value3}):
|
|
|
|
@example
|
|
iload 1
|
|
iload 2
|
|
imul
|
|
iload 3
|
|
iadd
|
|
istore 4
|
|
@end example
|
|
|
|
Let us demonstrate how this code would be translated, instruction
|
|
by instruction. We assume that we have a @code{stack} available,
|
|
which keeps track of the temporary values in the system. We also
|
|
assume that @code{jit_value_t} objects representing the local variables
|
|
are already stored in an array called @code{locals}.
|
|
|
|
@noindent
|
|
First, we load local variable 1 onto the stack:
|
|
|
|
@example
|
|
stack[size++] = jit_insn_load(func, locals[1]);
|
|
@end example
|
|
|
|
@noindent
|
|
We repeat this for local variable 2:
|
|
|
|
@example
|
|
stack[size++] = jit_insn_load(func, locals[2]);
|
|
@end example
|
|
|
|
@noindent
|
|
Now we pop these two values and push their multiplication:
|
|
|
|
@example
|
|
stack[size - 2] = jit_insn_mul(func, stack[size - 2], stack[size - 1]);
|
|
--size;
|
|
@end example
|
|
|
|
@noindent
|
|
Next, we need to push the value of local variable 3 and add it
|
|
to the product that we just computed:
|
|
|
|
@example
|
|
stack[size++] = jit_insn_load(func, locals[3]);
|
|
stack[size - 2] = jit_insn_add(func, stack[size - 2], stack[size - 1]);
|
|
--size;
|
|
@end example
|
|
|
|
@noindent
|
|
Finally, we store the result into local variable 4:
|
|
|
|
@example
|
|
jit_insn_store(func, locals[4], stack[--size]);
|
|
@end example
|
|
|
|
@noindent
|
|
Collecting up all of the above code, we get the following:
|
|
|
|
@example
|
|
stack[size++] = jit_insn_load(func, locals[1]);
|
|
stack[size++] = jit_insn_load(func, locals[2]);
|
|
stack[size - 2] = jit_insn_mul(func, stack[size - 2], stack[size - 1]);
|
|
--size;
|
|
stack[size++] = jit_insn_load(func, locals[3]);
|
|
stack[size - 2] = jit_insn_add(func, stack[size - 2], stack[size - 1]);
|
|
--size;
|
|
jit_insn_store(func, locals[4], stack[--size]);
|
|
@end example
|
|
|
|
The JIT will optimize away most of these temporary results, leaving
|
|
the final machine code that you expect.
|
|
|
|
If the virtual machine was register-based, then a slightly different
|
|
translation strategy would be used. Consider the following code,
|
|
which computes @code{reg4 = reg1 * reg2 + reg3}, with the intermediate
|
|
result stored temporarily in @code{reg5}:
|
|
|
|
@example
|
|
mul reg5, reg1, reg2
|
|
add reg4, reg5, reg3
|
|
@end example
|
|
|
|
You would start by allocating value objects for all of the registers
|
|
in your system (with @code{jit_value_create}):
|
|
|
|
@example
|
|
reg[1] = jit_value_create(func, jit_type_int);
|
|
reg[2] = jit_value_create(func, jit_type_int);
|
|
reg[3] = jit_value_create(func, jit_type_int);
|
|
reg[4] = jit_value_create(func, jit_type_int);
|
|
reg[5] = jit_value_create(func, jit_type_int);
|
|
@end example
|
|
|
|
@noindent
|
|
Then, the virtual register machine code is translated as follows:
|
|
|
|
@example
|
|
temp1 = jit_insn_mul(func, reg[1], reg[2]);
|
|
jit_insn_store(reg[5], temp1);
|
|
temp2 = jit_insn_add(func, reg[5], reg[3]);
|
|
jit_insn_store(reg[4], temp2);
|
|
@end example
|
|
|
|
Each virtual register machine instruction turns into two @code{libjit}
|
|
function calls. The JIT will normally optimize away the temporary
|
|
results. If the value in @code{reg5} is not used further down the code,
|
|
then the JIT may also be able to optimize @code{reg5} away.
|
|
|
|
The rest of this section describes the functions that are available
|
|
to create and manipulate values.
|
|
|
|
@*/
|
|
|
|
/*
|
|
* Allocate a new value from a function's memory pool.
|
|
*/
|
|
static jit_value_t
|
|
alloc_value(jit_function_t func, jit_type_t type)
|
|
{
|
|
/* Ensure that we have a builder for this function */
|
|
if(!_jit_function_ensure_builder(func))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
jit_value_t value = jit_memory_pool_alloc(&func->builder->value_pool, struct _jit_value);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
value->block = func->builder->current_block;
|
|
value->type = jit_type_copy(type);
|
|
value->reg = -1;
|
|
value->frame_offset = JIT_INVALID_FRAME_OFFSET;
|
|
value->index = -1;
|
|
|
|
return value;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_value_t jit_value_create (jit_function_t @var{func}, jit_type_t @var{type})
|
|
* Create a new value in the context of a function's current block.
|
|
* The value initially starts off as a block-specific temporary.
|
|
* It will be converted into a function-wide local variable if
|
|
* it is ever referenced from a different block. Returns NULL
|
|
* if out of memory.
|
|
*
|
|
* Note: It isn't possible to refer to global variables directly using
|
|
* values. If you need to access a global variable, then load its
|
|
* address into a temporary and use @code{jit_insn_load_relative}
|
|
* or @code{jit_insn_store_relative} to manipulate it. It simplifies
|
|
* the JIT if it can assume that all values are local.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_value_t
|
|
jit_value_create(jit_function_t func, jit_type_t type)
|
|
{
|
|
jit_value_t value = alloc_value(func, type);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
value->is_temporary = 1;
|
|
if(jit_type_has_tag(type, JIT_TYPETAG_VOLATILE))
|
|
{
|
|
value->is_volatile = 1;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_value_t jit_value_create_nint_constant (jit_function_t @var{func}, jit_type_t @var{type}, jit_nint @var{const_value})
|
|
* Create a new native integer constant in the specified function.
|
|
* Returns NULL if out of memory.
|
|
*
|
|
* The @var{type} parameter indicates the actual type of the constant,
|
|
* if it happens to be something other than @code{jit_type_nint}.
|
|
* For example, the following will create an unsigned byte constant:
|
|
*
|
|
* @example
|
|
* value = jit_value_create_nint_constant(func, jit_type_ubyte, 128);
|
|
* @end example
|
|
*
|
|
* This function can be used to create constants of type @code{jit_type_sbyte},
|
|
* @code{jit_type_ubyte}, @code{jit_type_short}, @code{jit_type_ushort},
|
|
* @code{jit_type_int}, @code{jit_type_uint}, @code{jit_type_nint},
|
|
* @code{jit_type_nuint}, and all pointer types.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_value_t
|
|
jit_value_create_nint_constant(jit_function_t func, jit_type_t type, jit_nint const_value)
|
|
{
|
|
jit_type_t stripped = 0;
|
|
if(!const_value)
|
|
{
|
|
/* Special cases: see if this is the NULL or zero constant */
|
|
stripped = jit_type_remove_tags(type);
|
|
if(stripped->kind == JIT_TYPE_SIGNATURE
|
|
|| stripped->kind == JIT_TYPE_PTR
|
|
|| stripped->kind == JIT_TYPE_NINT)
|
|
{
|
|
if(func && func->builder && func->builder->null_constant)
|
|
{
|
|
return func->builder->null_constant;
|
|
}
|
|
}
|
|
else if(stripped->kind == JIT_TYPE_INT)
|
|
{
|
|
if(func && func->builder && func->builder->zero_constant)
|
|
{
|
|
return func->builder->zero_constant;
|
|
}
|
|
}
|
|
}
|
|
|
|
jit_value_t value = alloc_value(func, type);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
value->is_constant = 1;
|
|
value->is_nint_constant = 1;
|
|
value->address = const_value;
|
|
|
|
if(stripped)
|
|
{
|
|
/* Special cases: see if we need to cache this constant for later */
|
|
if(stripped->kind == JIT_TYPE_SIGNATURE
|
|
|| stripped->kind == JIT_TYPE_PTR
|
|
|| stripped->kind == JIT_TYPE_NINT)
|
|
{
|
|
func->builder->null_constant = value;
|
|
}
|
|
else if(stripped->kind == JIT_TYPE_INT)
|
|
{
|
|
func->builder->zero_constant = value;
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_value_t jit_value_create_long_constant (jit_function_t @var{func}, jit_type_t @var{type}, jit_long @var{const_value})
|
|
* Create a new 64-bit integer constant in the specified
|
|
* function. This can also be used to create constants of
|
|
* type @code{jit_type_ulong}. Returns NULL if out of memory.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_value_t
|
|
jit_value_create_long_constant(jit_function_t func, jit_type_t type, jit_long const_value)
|
|
{
|
|
jit_value_t value = alloc_value(func, type);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
value->is_constant = 1;
|
|
#ifdef JIT_NATIVE_INT64
|
|
value->is_nint_constant = 1;
|
|
value->address = (jit_nint) const_value;
|
|
#else
|
|
value->address = (jit_nint) jit_malloc(sizeof(jit_long));
|
|
if(!value->address)
|
|
{
|
|
return 0;
|
|
}
|
|
*((jit_long *) value->address) = const_value;
|
|
value->free_address = 1;
|
|
#endif
|
|
return value;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_value_t jit_value_create_float32_constant (jit_function_t @var{func}, jit_type_t @var{type}, jit_float32 @var{const_value})
|
|
* Create a new 32-bit floating-point constant in the specified
|
|
* function. Returns NULL if out of memory.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_value_t
|
|
jit_value_create_float32_constant(jit_function_t func, jit_type_t type, jit_float32 const_value)
|
|
{
|
|
jit_value_t value = alloc_value(func, type);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
value->is_constant = 1;
|
|
value->address = (jit_nint) jit_malloc(sizeof(jit_float32));
|
|
if(!value->address)
|
|
{
|
|
return 0;
|
|
}
|
|
*((jit_float32 *) value->address) = const_value;
|
|
value->free_address = 1;
|
|
return value;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_value_t jit_value_create_float64_constant (jit_function_t @var{func}, jit_type_t @var{type}, jit_float64 @var{const_value})
|
|
* Create a new 64-bit floating-point constant in the specified
|
|
* function. Returns NULL if out of memory.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_value_t
|
|
jit_value_create_float64_constant(jit_function_t func, jit_type_t type, jit_float64 const_value)
|
|
{
|
|
jit_value_t value = alloc_value(func, type);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
value->is_constant = 1;
|
|
value->address = (jit_nint) jit_malloc(sizeof(jit_float64));
|
|
if(!value->address)
|
|
{
|
|
return 0;
|
|
}
|
|
*((jit_float64 *) value->address) = const_value;
|
|
value->free_address = 1;
|
|
return value;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_value_t jit_value_create_nfloat_constant (jit_function_t @var{func}, jit_type_t @var{type}, jit_nfloat @var{const_value})
|
|
* Create a new native floating-point constant in the specified
|
|
* function. Returns NULL if out of memory.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_value_t
|
|
jit_value_create_nfloat_constant(jit_function_t func, jit_type_t type, jit_nfloat const_value)
|
|
{
|
|
jit_value_t value = alloc_value(func, type);
|
|
if(!value)
|
|
{
|
|
return 0;
|
|
}
|
|
value->is_constant = 1;
|
|
value->address = (jit_nint) jit_malloc(sizeof(jit_nfloat));
|
|
if(!value->address)
|
|
{
|
|
return 0;
|
|
}
|
|
*((jit_nfloat *) value->address) = const_value;
|
|
value->free_address = 1;
|
|
return value;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_value_t jit_value_create_constant (jit_function_t @var{func}, const jit_constant_t *@var{const_value})
|
|
* Create a new constant from a generic constant structure in the specified
|
|
* function. Returns NULL if out of memory or if the type in
|
|
* @var{const_value} is not suitable for a constant.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_value_t
|
|
jit_value_create_constant(jit_function_t func, const jit_constant_t *const_value)
|
|
{
|
|
jit_type_t stripped = jit_type_remove_tags(const_value->type);
|
|
if(!stripped)
|
|
{
|
|
return 0;
|
|
}
|
|
switch(stripped->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 jit_value_create_nint_constant(func, const_value->type,
|
|
const_value->un.int_value);
|
|
|
|
case JIT_TYPE_NINT:
|
|
case JIT_TYPE_NUINT:
|
|
case JIT_TYPE_PTR:
|
|
case JIT_TYPE_SIGNATURE:
|
|
return jit_value_create_nint_constant(func, const_value->type,
|
|
const_value->un.nint_value);
|
|
|
|
case JIT_TYPE_LONG:
|
|
case JIT_TYPE_ULONG:
|
|
return jit_value_create_long_constant(func, const_value->type,
|
|
const_value->un.long_value);
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
return jit_value_create_float32_constant(func, const_value->type,
|
|
const_value->un.float32_value);
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
return jit_value_create_float64_constant(func, const_value->type,
|
|
const_value->un.float64_value);
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
return jit_value_create_nfloat_constant(func, const_value->type,
|
|
const_value->un.nfloat_value);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_value_t jit_value_get_param (jit_function_t @var{func}, unsigned int @var{param})
|
|
* Get the value that corresponds to a specified function parameter.
|
|
* Returns NULL if out of memory or @var{param} is invalid.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_value_t
|
|
jit_value_get_param(jit_function_t func, unsigned int param)
|
|
{
|
|
unsigned int num_params, current;
|
|
|
|
/* Ensure that we have a builder for this function */
|
|
if(!_jit_function_ensure_builder(func))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* Ensure valid param number. */
|
|
jit_type_t signature = func->signature;
|
|
num_params = jit_type_num_params(signature);
|
|
if(param >= num_params)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* If we have already created the values, then exit immediately */
|
|
jit_value_t *values = func->builder->param_values;
|
|
if(values)
|
|
{
|
|
return values[param];
|
|
}
|
|
|
|
/* Create the values for the first time */
|
|
values = (jit_value_t *) jit_calloc(num_params, sizeof(jit_value_t));
|
|
if(!values)
|
|
{
|
|
return 0;
|
|
}
|
|
func->builder->param_values = values;
|
|
for(current = 0; current < num_params; ++current)
|
|
{
|
|
jit_type_t type = jit_type_get_param(signature, current);
|
|
values[current] = jit_value_create(func, type);
|
|
if(values[current])
|
|
{
|
|
/* The value belongs to the entry block, no matter
|
|
where it happens to be created */
|
|
values[current]->block = func->builder->entry_block;
|
|
values[current]->is_parameter = 1;
|
|
}
|
|
}
|
|
|
|
/* Return the value block for the desired parameter */
|
|
return values[param];
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_value_t jit_value_get_struct_pointer (jit_function_t @var{func})
|
|
* Get the value that contains the structure return pointer for
|
|
* a function. If the function does not have a structure return pointer
|
|
* (i.e. structures are returned in registers), then this returns NULL.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_value_t
|
|
jit_value_get_struct_pointer(jit_function_t func)
|
|
{
|
|
jit_type_t type;
|
|
jit_value_t value;
|
|
|
|
/* Ensure that we have a builder for this function */
|
|
if(!_jit_function_ensure_builder(func))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
type = jit_type_remove_tags(jit_type_get_return(func->signature));
|
|
if(jit_type_is_struct(type) || jit_type_is_union(type))
|
|
{
|
|
if(jit_type_return_via_pointer(type))
|
|
{
|
|
if(!func->builder->struct_return)
|
|
{
|
|
type = jit_type_create_pointer(type, 1);
|
|
if(!type)
|
|
{
|
|
return 0;
|
|
}
|
|
value = jit_value_create(func, type);
|
|
func->builder->struct_return = value;
|
|
if(value)
|
|
{
|
|
/* The value belongs to the entry block, no matter
|
|
where it happens to be created */
|
|
value->block = func->builder->entry_block;
|
|
value->is_parameter = 1;
|
|
}
|
|
jit_type_free(type);
|
|
}
|
|
return func->builder->struct_return;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_value_is_temporary (jit_value_t @var{value})
|
|
* Determine if a value is temporary. i.e. its scope extends
|
|
* over a single block within its function.
|
|
* @end deftypefun
|
|
@*/
|
|
int
|
|
jit_value_is_temporary(jit_value_t value)
|
|
{
|
|
return value->is_temporary;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_value_is_local (jit_value_t @var{value})
|
|
* Determine if a value is local. i.e. its scope extends
|
|
* over multiple blocks within its function.
|
|
* @end deftypefun
|
|
@*/
|
|
int
|
|
jit_value_is_local(jit_value_t value)
|
|
{
|
|
return value->is_local;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_value_is_constant (jit_value_t @var{value})
|
|
* Determine if a value is a constant.
|
|
* @end deftypefun
|
|
@*/
|
|
int
|
|
jit_value_is_constant(jit_value_t value)
|
|
{
|
|
return value->is_constant;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_value_is_parameter (jit_value_t @var{value})
|
|
* Determine if a value is a function parameter.
|
|
* @end deftypefun
|
|
@*/
|
|
int
|
|
jit_value_is_parameter(jit_value_t value)
|
|
{
|
|
return value->is_parameter;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun void jit_value_ref (jit_function_t @var{func}, jit_value_t @var{value})
|
|
* Create a reference to the specified @var{value} from the current
|
|
* block in @var{func}. This will convert a temporary value into
|
|
* a local value if @var{value} is being referenced from a different
|
|
* block than its original.
|
|
*
|
|
* It is not necessary that @var{func} be the same function as the
|
|
* one where the value was originally created. It may be a nested
|
|
* function, referring to a local variable in its parent function.
|
|
* @end deftypefun
|
|
@*/
|
|
void
|
|
jit_value_ref(jit_function_t func, jit_value_t value)
|
|
{
|
|
/* Ensure that we have a builder for this function */
|
|
if(!_jit_function_ensure_builder(func))
|
|
{
|
|
return;
|
|
}
|
|
|
|
value->usage_count++;
|
|
if(value->is_temporary)
|
|
{
|
|
if(value->block->func != func)
|
|
{
|
|
/* Reference from a different function: local and addressable */
|
|
value->is_temporary = 0;
|
|
value->is_local = 1;
|
|
value->is_addressable = 1;
|
|
|
|
/* Mark the two functions as not leaves because we will need
|
|
them to set up proper frame pointers to allow us to access
|
|
the local variable across the nested function boundary */
|
|
value->block->func->builder->non_leaf = 1;
|
|
func->builder->non_leaf = 1;
|
|
}
|
|
else if(value->block != func->builder->current_block)
|
|
{
|
|
/* Reference from another block in same function: local */
|
|
value->is_temporary = 0;
|
|
value->is_local = 1;
|
|
if(_jit_gen_is_global_candidate(value->type))
|
|
{
|
|
value->global_candidate = 1;
|
|
}
|
|
}
|
|
}
|
|
else if(value->is_local && value->block->func != func)
|
|
{
|
|
/* Convert a previously local value into an addressable one */
|
|
value->is_addressable = 1;
|
|
value->block->func->builder->non_leaf = 1;
|
|
func->builder->non_leaf = 1;
|
|
}
|
|
}
|
|
|
|
/* TODO: seems to be unused */
|
|
void _jit_value_ref_params(jit_function_t func)
|
|
{
|
|
unsigned int num_params;
|
|
unsigned int param;
|
|
if(func->builder->param_values)
|
|
{
|
|
num_params = jit_type_num_params(func->signature);
|
|
for(param = 0; param < num_params; ++param)
|
|
{
|
|
jit_value_ref(func, func->builder->param_values[param]);
|
|
}
|
|
}
|
|
jit_value_ref(func, func->builder->struct_return);
|
|
jit_value_ref(func, func->builder->parent_frame);
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun void jit_value_set_volatile (jit_value_t @var{value})
|
|
* Set a flag on a value to indicate that it is volatile. The contents
|
|
* of the value must always be reloaded from memory, never from a
|
|
* cached register copy.
|
|
* @end deftypefun
|
|
@*/
|
|
void
|
|
jit_value_set_volatile(jit_value_t value)
|
|
{
|
|
value->is_volatile = 1;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_value_is_volatile (jit_value_t @var{value})
|
|
* Determine if a value is volatile.
|
|
* @end deftypefun
|
|
@*/
|
|
int
|
|
jit_value_is_volatile(jit_value_t value)
|
|
{
|
|
return value->is_volatile;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun void jit_value_set_addressable (jit_value_t @var{value})
|
|
* Set a flag on a value to indicate that it is addressable.
|
|
* This should be used when you want to take the address of a
|
|
* value (e.g. @code{&variable} in C). The value is guaranteed
|
|
* to not be stored in a register across a function call.
|
|
* If you refer to a value from a nested function (@code{jit_value_ref}),
|
|
* then the value will be automatically marked as addressable.
|
|
* @end deftypefun
|
|
@*/
|
|
void
|
|
jit_value_set_addressable(jit_value_t value)
|
|
{
|
|
value->is_addressable = 1;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_value_is_addressable (jit_value_t @var{value})
|
|
* Determine if a value is addressable.
|
|
* @end deftypefun
|
|
@*/
|
|
int
|
|
jit_value_is_addressable(jit_value_t value)
|
|
{
|
|
return value->is_addressable;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_value_get_type (jit_value_t @var{value})
|
|
* Get the type that is associated with a value.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t
|
|
jit_value_get_type(jit_value_t value)
|
|
{
|
|
return value->type;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_function_t jit_value_get_function (jit_value_t @var{value})
|
|
* Get the function which owns a particular @var{value}.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_function_t
|
|
jit_value_get_function(jit_value_t value)
|
|
{
|
|
return value->block->func;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_block_t jit_value_get_block (jit_value_t @var{value})
|
|
* Get the block which owns a particular @var{value}.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_block_t
|
|
jit_value_get_block(jit_value_t value)
|
|
{
|
|
return value->block;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_context_t jit_value_get_context (jit_value_t @var{value})
|
|
* Get the context which owns a particular @var{value}.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_context_t
|
|
jit_value_get_context(jit_value_t value)
|
|
{
|
|
return value->block->func->context;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_constant_t jit_value_get_constant (jit_value_t @var{value})
|
|
* Get the constant value within a particular @var{value}. The returned
|
|
* structure's @code{type} field will be @code{jit_type_void} if
|
|
* @code{value} is not a constant.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_constant_t
|
|
jit_value_get_constant(jit_value_t value)
|
|
{
|
|
jit_constant_t result;
|
|
if(!value->is_constant)
|
|
{
|
|
result.type = jit_type_void;
|
|
return result;
|
|
}
|
|
result.type = value->type;
|
|
switch(jit_type_remove_tags(value->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:
|
|
result.un.int_value = (jit_int) value->address;
|
|
break;
|
|
|
|
case JIT_TYPE_NINT:
|
|
case JIT_TYPE_NUINT:
|
|
case JIT_TYPE_PTR:
|
|
case JIT_TYPE_SIGNATURE:
|
|
result.un.nint_value = value->address;
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
case JIT_TYPE_ULONG:
|
|
#ifdef JIT_NATIVE_INT64
|
|
result.un.long_value = (jit_long) value->address;
|
|
#else
|
|
result.un.long_value = *((jit_long *) value->address);
|
|
#endif
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
result.un.float32_value = *((jit_float32 *) value->address);
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
result.un.float64_value = *((jit_float64 *) value->address);
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
result.un.nfloat_value = *((jit_nfloat *) value->address);
|
|
break;
|
|
|
|
default:
|
|
result.type = jit_type_void;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_nint jit_value_get_nint_constant (jit_value_t @var{value})
|
|
* Get the constant value within a particular @var{value}, assuming
|
|
* that its type is compatible with @code{jit_type_nint}.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_nint
|
|
jit_value_get_nint_constant(jit_value_t value)
|
|
{
|
|
if(!value->is_nint_constant)
|
|
{
|
|
return 0;
|
|
}
|
|
return (jit_nint) value->address;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_nint jit_value_get_long_constant (jit_value_t @var{value})
|
|
* Get the constant value within a particular @var{value}, assuming
|
|
* that its type is compatible with @code{jit_type_long}.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_long
|
|
jit_value_get_long_constant(jit_value_t value)
|
|
{
|
|
if(!value->is_constant)
|
|
{
|
|
return 0;
|
|
}
|
|
switch(jit_type_normalize(value->type)->kind)
|
|
{
|
|
case JIT_TYPE_LONG:
|
|
case JIT_TYPE_ULONG:
|
|
#ifdef JIT_NATIVE_INT64
|
|
return (jit_long) value->address;
|
|
#else
|
|
return *((jit_long *) value->address);
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_float32 jit_value_get_float32_constant (jit_value_t @var{value})
|
|
* Get the constant value within a particular @var{value}, assuming
|
|
* that its type is compatible with @code{jit_type_float32}.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_float32
|
|
jit_value_get_float32_constant(jit_value_t value)
|
|
{
|
|
if(!value->is_constant || jit_type_normalize(value->type)->kind != JIT_TYPE_FLOAT32)
|
|
{
|
|
return (jit_float32) 0.0;
|
|
}
|
|
return *((jit_float32 *) value->address);
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_float64 jit_value_get_float64_constant (jit_value_t @var{value})
|
|
* Get the constant value within a particular @var{value}, assuming
|
|
* that its type is compatible with @code{jit_type_float64}.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_float64
|
|
jit_value_get_float64_constant(jit_value_t value)
|
|
{
|
|
if(!value->is_constant || jit_type_normalize(value->type)->kind != JIT_TYPE_FLOAT64)
|
|
{
|
|
return (jit_float64) 0.0;
|
|
}
|
|
return *((jit_float64 *) value->address);
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_nfloat jit_value_get_nfloat_constant (jit_value_t @var{value})
|
|
* Get the constant value within a particular @var{value}, assuming
|
|
* that its type is compatible with @code{jit_type_nfloat}.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_nfloat
|
|
jit_value_get_nfloat_constant(jit_value_t value)
|
|
{
|
|
if(!value->is_constant || jit_type_normalize(value->type)->kind != JIT_TYPE_NFLOAT)
|
|
{
|
|
return (jit_nfloat) 0.0;
|
|
}
|
|
return *((jit_nfloat *) value->address);
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_value_is_true (jit_value_t @var{value})
|
|
* Determine if @var{value} is constant and non-zero.
|
|
* @end deftypefun
|
|
@*/
|
|
int
|
|
jit_value_is_true(jit_value_t value)
|
|
{
|
|
if(!value || !value->is_constant)
|
|
{
|
|
return 0;
|
|
}
|
|
if(value->is_nint_constant)
|
|
{
|
|
return (value->address != 0);
|
|
}
|
|
switch(jit_type_remove_tags(value->type)->kind)
|
|
{
|
|
case JIT_TYPE_LONG:
|
|
case JIT_TYPE_ULONG:
|
|
return (jit_value_get_long_constant(value) != 0);
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
return (jit_value_get_float32_constant(value) != (jit_float32) 0.0);
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
return (jit_value_get_float64_constant(value) != (jit_float64) 0.0);
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
return (jit_value_get_nfloat_constant(value) != (jit_nfloat) 0.0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_constant_convert (jit_constant_t *@var{result}, const jit_constant_t *@var{value}, jit_type_t @var{type}, int @var{overflow_check})
|
|
* Convert a the constant @var{value} into a new @var{type}, and
|
|
* return its value in @var{result}. Returns zero if the conversion
|
|
* is not possible, usually due to overflow.
|
|
* @end deftypefun
|
|
@*/
|
|
int
|
|
jit_constant_convert(jit_constant_t *result, const jit_constant_t *value, jit_type_t type,
|
|
int overflow_check)
|
|
{
|
|
jit_type_t srctype;
|
|
jit_type_t desttype;
|
|
|
|
/* Normalize the source and destination types. The source type
|
|
is also promoted, to reduce the number of cases in the
|
|
inner switch statements below */
|
|
srctype = jit_type_promote_int(jit_type_normalize(value->type));
|
|
if(!srctype)
|
|
{
|
|
return 0;
|
|
}
|
|
desttype = jit_type_normalize(type);
|
|
if(!desttype)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* Determine what kind of conversion to perform */
|
|
result->type = type;
|
|
switch(desttype->kind)
|
|
{
|
|
case JIT_TYPE_SBYTE:
|
|
/* Convert to a signed 8-bit integer */
|
|
switch(srctype->kind)
|
|
{
|
|
case JIT_TYPE_INT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_int_to_sbyte_ovf(&result->un.int_value,
|
|
value->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_int_to_sbyte(value->un.int_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_uint_to_int_ovf(&result->un.int_value,
|
|
value->un.uint_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_sbyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_int_to_sbyte(value->un.int_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_long_to_int_ovf(&result->un.int_value,
|
|
value->un.long_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_sbyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_sbyte(jit_long_to_int(value->un.long_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_ulong_to_int_ovf(&result->un.int_value,
|
|
value->un.ulong_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_sbyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_sbyte(jit_ulong_to_int(value->un.ulong_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float32_to_int_ovf(&result->un.int_value,
|
|
value->un.float32_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_sbyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_sbyte(jit_float32_to_int(value->un.float32_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float64_to_int_ovf(&result->un.int_value,
|
|
value->un.float64_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_sbyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_sbyte(jit_float64_to_int(value->un.float64_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_nfloat_to_int_ovf(&result->un.int_value,
|
|
value->un.nfloat_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_sbyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_sbyte(jit_nfloat_to_int(value->un.nfloat_value));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UBYTE:
|
|
/* Convert to an unsigned 8-bit integer */
|
|
switch(srctype->kind)
|
|
{
|
|
case JIT_TYPE_INT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_int_to_ubyte_ovf(&result->un.int_value,
|
|
value->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_int_to_ubyte(value->un.int_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_uint_to_int_ovf(&result->un.int_value,
|
|
value->un.uint_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ubyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_int_to_ubyte(value->un.int_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_long_to_int_ovf(&result->un.int_value,
|
|
value->un.long_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ubyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_ubyte(jit_long_to_int(value->un.long_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_ulong_to_int_ovf(&result->un.int_value,
|
|
value->un.ulong_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ubyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_ubyte(jit_ulong_to_int(value->un.ulong_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float32_to_int_ovf(&result->un.int_value,
|
|
value->un.float32_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ubyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_ubyte(jit_float32_to_int(value->un.float32_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float64_to_int_ovf(&result->un.int_value,
|
|
value->un.float64_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ubyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_ubyte(jit_float64_to_int(value->un.float64_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_nfloat_to_int_ovf(&result->un.int_value,
|
|
value->un.nfloat_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ubyte_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_ubyte(jit_nfloat_to_int(value->un.nfloat_value));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_SHORT:
|
|
/* Convert to a signed 16-bit integer */
|
|
switch(srctype->kind)
|
|
{
|
|
case JIT_TYPE_INT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_int_to_short_ovf(&result->un.int_value,
|
|
value->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_int_to_short(value->un.int_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_uint_to_int_ovf(&result->un.int_value,
|
|
value->un.uint_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_short_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_int_to_short(value->un.int_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_long_to_int_ovf(&result->un.int_value,
|
|
value->un.long_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_short_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_short(
|
|
jit_long_to_int(value->un.long_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_ulong_to_int_ovf(&result->un.int_value,
|
|
value->un.ulong_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_short_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_short(
|
|
jit_ulong_to_int(value->un.ulong_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float32_to_int_ovf(&result->un.int_value,
|
|
value->un.float32_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_short_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_short(
|
|
jit_float32_to_int(value->un.float32_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float64_to_int_ovf(&result->un.int_value,
|
|
value->un.float64_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_short_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_short(
|
|
jit_float64_to_int(value->un.float64_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_nfloat_to_int_ovf(&result->un.int_value,
|
|
value->un.nfloat_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_short_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_short(
|
|
jit_nfloat_to_int(value->un.nfloat_value));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_USHORT:
|
|
/* Convert to an unsigned 16-bit integer */
|
|
switch(srctype->kind)
|
|
{
|
|
case JIT_TYPE_INT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_int_to_ushort_ovf(&result->un.int_value,
|
|
value->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_int_to_ushort(value->un.int_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_uint_to_int_ovf(&result->un.int_value,
|
|
value->un.uint_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ushort_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_int_to_ushort(value->un.int_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_long_to_int_ovf(&result->un.int_value,
|
|
value->un.long_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ushort_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_ushort(
|
|
jit_long_to_int(value->un.long_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_ulong_to_int_ovf(&result->un.int_value,
|
|
value->un.ulong_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ushort_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_ushort(
|
|
jit_ulong_to_int(value->un.ulong_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float32_to_int_ovf(&result->un.int_value,
|
|
value->un.float32_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ushort_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_ushort(
|
|
jit_float32_to_int(value->un.float32_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float64_to_int_ovf(&result->un.int_value,
|
|
value->un.float64_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ushort_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_ushort(
|
|
jit_float64_to_int(value->un.float64_value));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_nfloat_to_int_ovf(&result->un.int_value,
|
|
value->un.nfloat_value))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!jit_int_to_ushort_ovf(&result->un.int_value,
|
|
result->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value =
|
|
jit_int_to_ushort(
|
|
jit_nfloat_to_int(value->un.nfloat_value));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_INT:
|
|
/* Convert to a signed 32-bit integer */
|
|
switch(srctype->kind)
|
|
{
|
|
case JIT_TYPE_INT:
|
|
result->un.int_value = value->un.int_value;
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_uint_to_int_ovf(&result->un.int_value,
|
|
value->un.uint_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_uint_to_int(value->un.uint_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_long_to_int_ovf(&result->un.int_value,
|
|
value->un.long_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_long_to_int(value->un.long_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_ulong_to_int_ovf(&result->un.int_value,
|
|
value->un.ulong_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_ulong_to_int(value->un.ulong_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float32_to_int_ovf(&result->un.int_value,
|
|
value->un.float32_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_float32_to_int(value->un.float32_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float64_to_int_ovf(&result->un.int_value,
|
|
value->un.float64_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_float64_to_int(value->un.float64_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_nfloat_to_int_ovf(&result->un.int_value,
|
|
value->un.nfloat_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.int_value = jit_nfloat_to_int(value->un.nfloat_value);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
/* Convert to an unsigned 32-bit integer */
|
|
switch(srctype->kind)
|
|
{
|
|
case JIT_TYPE_INT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_int_to_uint_ovf(&result->un.uint_value,
|
|
value->un.uint_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.uint_value = jit_int_to_uint(value->un.int_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
result->un.uint_value = value->un.uint_value;
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_long_to_uint_ovf(&result->un.uint_value,
|
|
value->un.long_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.uint_value = jit_long_to_uint(value->un.long_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_ulong_to_uint_ovf(&result->un.uint_value,
|
|
value->un.ulong_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.uint_value = jit_ulong_to_uint(value->un.ulong_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float32_to_uint_ovf(&result->un.uint_value,
|
|
value->un.float32_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.uint_value = jit_float32_to_uint(value->un.float32_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float64_to_uint_ovf(&result->un.uint_value,
|
|
value->un.float64_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.uint_value = jit_float64_to_uint(value->un.float64_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_nfloat_to_uint_ovf(&result->un.uint_value,
|
|
value->un.nfloat_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.uint_value = jit_nfloat_to_uint(value->un.nfloat_value);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
/* Convert to a signed 64-bit integer */
|
|
switch(srctype->kind)
|
|
{
|
|
case JIT_TYPE_INT:
|
|
result->un.long_value =
|
|
jit_int_to_long(value->un.int_value);
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
result->un.long_value =
|
|
jit_uint_to_long(value->un.int_value);
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
result->un.long_value = value->un.long_value;
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_ulong_to_long_ovf(&result->un.long_value,
|
|
value->un.ulong_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.long_value = jit_ulong_to_long(value->un.ulong_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float32_to_long_ovf(&result->un.long_value,
|
|
value->un.float32_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.long_value = jit_float32_to_long(value->un.float32_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float64_to_long_ovf(&result->un.long_value,
|
|
value->un.float64_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.long_value = jit_float64_to_long(value->un.float64_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_nfloat_to_long_ovf(&result->un.long_value,
|
|
value->un.nfloat_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.long_value = jit_nfloat_to_long(value->un.nfloat_value);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
/* Convert to an unsigned 64-bit integer */
|
|
switch(srctype->kind)
|
|
{
|
|
case JIT_TYPE_INT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_int_to_ulong_ovf(&result->un.ulong_value,
|
|
value->un.int_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.ulong_value = jit_int_to_ulong(value->un.int_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
result->un.ulong_value =
|
|
jit_uint_to_ulong(value->un.uint_value);
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_long_to_ulong_ovf(&result->un.ulong_value,
|
|
value->un.long_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.ulong_value = jit_long_to_ulong(value->un.long_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
result->un.ulong_value = value->un.ulong_value;
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float32_to_ulong_ovf(&result->un.ulong_value,
|
|
value->un.float32_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.ulong_value = jit_float32_to_ulong(value->un.float32_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_float64_to_ulong_ovf(&result->un.ulong_value,
|
|
value->un.float64_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.ulong_value = jit_float64_to_ulong(value->un.float64_value);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
if(overflow_check)
|
|
{
|
|
if(!jit_nfloat_to_ulong_ovf(&result->un.ulong_value,
|
|
value->un.nfloat_value))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result->un.ulong_value = jit_nfloat_to_ulong(value->un.nfloat_value);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
/* Convert to a 32-bit float */
|
|
switch(srctype->kind)
|
|
{
|
|
case JIT_TYPE_INT:
|
|
result->un.float32_value = jit_int_to_float32(value->un.int_value);
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
result->un.float32_value = jit_uint_to_float32(value->un.uint_value);
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
result->un.float32_value = jit_long_to_float32(value->un.long_value);
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
result->un.float32_value = jit_ulong_to_float32(value->un.ulong_value);
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
result->un.float32_value = value->un.float32_value;
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
result->un.float32_value = jit_float64_to_float32(value->un.float64_value);
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
result->un.float32_value = jit_nfloat_to_float32(value->un.nfloat_value);
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
/* Convert to a 64-bit float */
|
|
switch(srctype->kind)
|
|
{
|
|
case JIT_TYPE_INT:
|
|
result->un.float64_value = jit_int_to_float64(value->un.int_value);
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
result->un.float64_value = jit_uint_to_float64(value->un.uint_value);
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
result->un.float64_value = jit_long_to_float64(value->un.long_value);
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
result->un.float64_value = jit_ulong_to_float64(value->un.ulong_value);
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
result->un.float64_value = jit_float32_to_float64(value->un.float32_value);
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
result->un.float64_value = value->un.float64_value;
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
result->un.float64_value = jit_nfloat_to_float64(value->un.nfloat_value);
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
/* Convert to a native float */
|
|
switch(srctype->kind)
|
|
{
|
|
case JIT_TYPE_INT:
|
|
result->un.nfloat_value = jit_int_to_nfloat(value->un.int_value);
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
result->un.nfloat_value = jit_uint_to_nfloat(value->un.uint_value);
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
result->un.nfloat_value = jit_long_to_nfloat(value->un.long_value);
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
result->un.nfloat_value = jit_ulong_to_nfloat(value->un.ulong_value);
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
result->un.nfloat_value = jit_float32_to_nfloat(value->un.float32_value);
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
result->un.nfloat_value = jit_float64_to_nfloat(value->un.float64_value);
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
result->un.nfloat_value = value->un.nfloat_value;
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
_jit_value_free(void *_value)
|
|
{
|
|
jit_value_t value = (jit_value_t) _value;
|
|
jit_type_free(value->type);
|
|
if(value->free_address && value->address)
|
|
{
|
|
/* We need to free the memory for a large constant */
|
|
jit_free((void *) value->address);
|
|
}
|
|
}
|
|
|