Esempio n. 1
0
/*@
 * @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;
}
Esempio n. 2
0
/*@
 * @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;
}
Esempio n. 3
0
/*@
 * @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;
}
Esempio n. 4
0
File: jit-dump.c Progetto: 8l/lllm
/*@
 * @deftypefun void jit_dump_type (FILE *@var{stream}, jit_type_t @var{type})
 * Dump the name of a type to a stdio stream.
 * @end deftypefun
@*/
void jit_dump_type(FILE *stream, jit_type_t type)
{
	const char *name;
	type = jit_type_remove_tags(type);
	if(!type || !stream)
	{
		return;
	}
	switch(type->kind)
	{
		case JIT_TYPE_VOID:		name = "void"; break;
		case JIT_TYPE_SBYTE:		name = "sbyte"; break;
		case JIT_TYPE_UBYTE:		name = "ubyte"; break;
		case JIT_TYPE_SHORT:		name = "short"; break;
		case JIT_TYPE_USHORT:		name = "ushort"; break;
		case JIT_TYPE_INT:		name = "int"; break;
		case JIT_TYPE_UINT:		name = "uint"; break;
		case JIT_TYPE_NINT:		name = "nint"; break;
		case JIT_TYPE_NUINT:		name = "nuint"; break;
		case JIT_TYPE_LONG:		name = "long"; break;
		case JIT_TYPE_ULONG:		name = "ulong"; break;
		case JIT_TYPE_FLOAT32:		name = "float32"; break;
		case JIT_TYPE_FLOAT64:		name = "float64"; break;
		case JIT_TYPE_NFLOAT:		name = "nfloat"; break;

		case JIT_TYPE_STRUCT:
		{
			fprintf(stream, "struct<%u>",
				(unsigned int)(jit_type_get_size(type)));
			return;
		}
		/* Not reached */

		case JIT_TYPE_UNION:
		{
			fprintf(stream, "union<%u>",
				(unsigned int)(jit_type_get_size(type)));
			return;
		}
		/* Not reached */

		case JIT_TYPE_SIGNATURE:	name = "signature"; break;
		case JIT_TYPE_PTR:		name = "ptr"; break;
		default: 			name = "<unknown-type>"; break;
	}
	fputs(name, stream);
}
Esempio n. 5
0
/*@
 * @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;
}
Esempio n. 6
0
/*
 * Calculate the size of the argument area for an interpreted function.
 */
unsigned int _jit_interp_calculate_arg_size
		(jit_function_t func, jit_type_t signature)
{
	unsigned int size = 0;
	jit_type_t type;
	unsigned int num_params;
	unsigned int param;

	/* Determine if we need nested parameter information */
	if(func->nested_parent)
	{
		size += 2 * sizeof(jit_item);
	}

	/* Determine if we need a structure pointer argument */
	type = jit_type_get_return(signature);
	if(jit_type_return_via_pointer(type))
	{
		size += sizeof(jit_item);
	}

	/* Calculate the total size of the regular arguments */
	num_params = jit_type_num_params(signature);
	for(param = 0; param < num_params; ++param)
	{
		type = jit_type_get_param(signature, param);
		type = jit_type_remove_tags(type);
		if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
		{
			size += JIT_NUM_ITEMS_IN_STRUCT(jit_type_get_size(type)) *
					sizeof(jit_item);
		}
		else
		{
			size += sizeof(jit_item);
		}
	}

	/* Return the final size to the caller */
	return size;
}
Esempio n. 7
0
/*@
 * @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;
}
Esempio n. 8
0
/*@
 * @deftypefun int _jit_create_call_return_insns (jit_function_t @var{func}, jit_type_t @var{signature}, jit_value_t *@var{args}, unsigned int @var{num_args}, jit_value_t @var{return_value}, int @var{is_nested})
 * Create instructions within @var{func} to clean up after a function call
 * and to place the function's result into @var{return_value}.
 * This should use @code{jit_insn_pop_stack} to pop values off the system
 * stack and @code{jit_insn_return_reg} to tell @code{libjit} which
 * register contains the return value.  In the case of a @code{void}
 * function, @var{return_value} will be NULL.
 *
 * Note: the argument values are passed again because it may not be possible
 * to determine how many bytes to pop from the stack from the @var{signature}
 * alone; especially if the called function is vararg.
 * @end deftypefun
@*/
int _jit_create_call_return_insns
	(jit_function_t func, jit_type_t signature,
	 jit_value_t *args, unsigned int num_args,
	 jit_value_t return_value, int is_nested)
{
	jit_nint pop_items;
	unsigned int size;
	jit_type_t return_type;
	int ptr_return;

	/* Calculate the number of items that we need to pop */
	pop_items = 0;
	while(num_args > 0)
	{
		--num_args;
		size = jit_type_get_size(jit_value_get_type(args[num_args]));
		pop_items += JIT_NUM_ITEMS_IN_STRUCT(size);
	}
	return_type = jit_type_get_return(signature);
	return_type = jit_type_remove_tags(return_type);
	ptr_return = jit_type_return_via_pointer(return_type);
	if(ptr_return)
	{
		++pop_items;
	}
	if(is_nested)
	{
		/* The interpreter needs two arguments for the parent frame info */
		pop_items += 2;
	}

	/* Pop the items from the system stack */
	if(pop_items > 0)
	{
		if(!jit_insn_pop_stack(func, pop_items))
		{
			return 0;
		}
	}

	/* Bail out now if we don't need to worry about return values */
	if(!return_value || ptr_return)
	{
		return 1;
	}

	/* Structure values must be flushed into the frame, and
	   everything else ends up in the top-most stack register */
	if(jit_type_is_struct(return_type) || jit_type_is_union(return_type))
	{
		if(!jit_insn_flush_struct(func, return_value))
		{
			return 0;
		}
	}
	else if(return_type->kind != JIT_TYPE_VOID)
	{
		if(!jit_insn_return_reg(func, return_value, 0))
		{
			return 0;
		}
	}

	/* Everything is back where it needs to be */
	return 1;
}
Esempio n. 9
0
/*@
 * @deftypefun int _jit_create_call_setup_insns (jit_function_t @var{func}, jit_type_t @var{signature}, jit_value_t *@var{args}, unsigned int @var{num_args}, int @var{is_nested}, int @var{nested_level}, jit_value_t *@var{struct_return}, int @var{flags})
 * Create instructions within @var{func} necessary to set up for a
 * function call to a function with the specified @var{signature}.
 * Use @code{jit_insn_push} to push values onto the system stack,
 * or @code{jit_insn_outgoing_reg} to copy values into call registers.
 *
 * If @var{is_nested} is non-zero, then it indicates that we are calling a
 * nested function within the current function's nested relationship tree.
 * The @var{nested_level} value will be -1 to call a child, zero to call a
 * sibling of @var{func}, 1 to call a sibling of the parent, 2 to call
 * a sibling of the grandparent, etc.  The @code{jit_insn_setup_for_nested}
 * instruction should be used to create the nested function setup code.
 *
 * If the function returns a structure by pointer, then @var{struct_return}
 * must be set to a new local variable that will contain the returned
 * structure.  Otherwise it should be set to NULL.
 * @end deftypefun
@*/
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 nested_level, jit_value_t *struct_return, int flags)
{
	jit_type_t type;
	jit_type_t vtype;
	jit_value_t value;
	unsigned int arg_num;
	jit_nint offset;
	jit_nuint size;

	/* Regular or tail call? */
	if((flags & JIT_CALL_TAIL) == 0)
	{
		/* Push all of the arguments in reverse order */
		while(num_args > 0)
		{
			--num_args;
			type = jit_type_get_param(signature, num_args);
			type = jit_type_remove_tags(type);
			if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
			{
				/* If the value is a pointer, then we are pushing a structure
				   argument by pointer rather than by local variable */
				vtype = jit_type_normalize(jit_value_get_type(args[num_args]));
				if(vtype->kind <= JIT_TYPE_MAX_PRIMITIVE)
				{
					if(!jit_insn_push_ptr(func, args[num_args], type))
					{
						return 0;
					}
					continue;
				}
			}
			if(!jit_insn_push(func, args[num_args]))
			{
				return 0;
			}
		}

		/* Do we need to add a structure return pointer argument? */
		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;
			value = jit_insn_address_of(func, value);
			if(!value)
			{
				return 0;
			}
			if(!jit_insn_push(func, value))
			{
				return 0;
			}
		}
		else if((flags & JIT_CALL_NATIVE) != 0)
		{
			/* Native calls always return a return area pointer */
			if(!jit_insn_push_return_area_ptr(func))
			{
				return 0;
			}
			*struct_return = 0;
		}
		else
		{
			*struct_return = 0;
		}

		/* Do we need to add nested function scope information? */
		if(is_nested)
		{
			if(!jit_insn_setup_for_nested(func, nested_level, -1))
			{
				return 0;
			}
		}
	}
	else
	{
		/* Copy the arguments into our own parameter slots */
		offset = -1;
		if(func->nested_parent)
		{
			offset -= 2;
		}
		type = jit_type_get_return(signature);
		if(jit_type_return_via_pointer(type))
		{
			--offset;
		}
		for(arg_num = 0; arg_num < num_args; ++arg_num)
		{
			type = jit_type_get_param(signature, arg_num);
			value = jit_value_create(func, type);
			if(!value)
			{
				return 0;
			}
			if(!jit_insn_outgoing_frame_posn(func, value, offset))
			{
				return 0;
			}
			type = jit_type_remove_tags(type);
			size = jit_type_get_size(type);
			offset -= (jit_nint)(JIT_NUM_ITEMS_IN_STRUCT(size));
			if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
			{
				/* If the value is a pointer, then we are pushing a structure
				   argument by pointer rather than by local variable */
				vtype = jit_type_normalize(jit_value_get_type(args[arg_num]));
				if(vtype->kind <= JIT_TYPE_MAX_PRIMITIVE)
				{
					value = jit_insn_address_of(func, value);
					if(!value)
					{
						return 0;
					}
					if(!jit_insn_memcpy
							(func, value, args[arg_num],
							 jit_value_create_nint_constant
								(func, jit_type_nint, (jit_nint)size)))
					{
						return 0;
					}
					continue;
				}
			}
			if(!jit_insn_store(func, value, args[arg_num]))
			{
				return 0;
			}
		}
		*struct_return = 0;
	}

	/* The call is ready to proceed */
	return 1;
}
Esempio n. 10
0
/*@
 * @deftypefun int _jit_create_entry_insns (jit_function_t @var{func})
 * Create instructions in the entry block to initialize the
 * registers and frame offsets that contain the parameters.
 * Returns zero if out of memory.
 *
 * This function is called when a builder is initialized.  It should
 * scan the signature and decide which register or frame position
 * contains each of the parameters and then call either
 * @code{jit_insn_incoming_reg} or @code{jit_insn_incoming_frame_posn}
 * to notify @code{libjit} of the location.
 * @end deftypefun
@*/
int _jit_create_entry_insns(jit_function_t func)
{
	jit_type_t signature = func->signature;
	jit_type_t type;
	jit_nint offset;
	jit_value_t value;
	unsigned int num_params;
	unsigned int param;

	/* Reset the frame size for this function */
	func->builder->frame_size = 0;

	/* The starting parameter offset.  We use negative offsets to indicate
	   an offset into the "args" block, and positive offsets to indicate
	   an offset into the "frame" block.  The negative values will be
	   flipped when we output the argument opcodes for interpretation */
	offset = -1;

	/* If the function is nested, then we need two extra parameters
	   to pass the pointer to the parent's local variables and arguments */
	if(func->nested_parent)
	{
		offset -= 2;
	}

	/* Allocate the structure return pointer */
	value = jit_value_get_struct_pointer(func);
	if(value)
	{
		if(!jit_insn_incoming_frame_posn(func, value, offset))
		{
			return 0;
		}
		--offset;
	}

	/* Allocate the parameter offsets */
	num_params = jit_type_num_params(signature);
	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(!jit_insn_incoming_frame_posn(func, value,
							 offset - _jit_int_lowest_byte()))
			{
				return 0;
			}
			--offset;
			break;

		case JIT_TYPE_SHORT:
		case JIT_TYPE_USHORT:
			if(!jit_insn_incoming_frame_posn(func, value,
							 offset - _jit_int_lowest_short()))
			{
				return 0;
			}
			--offset;
			break;

		case JIT_TYPE_INT:
		case JIT_TYPE_UINT:
		case JIT_TYPE_NINT:
		case JIT_TYPE_NUINT:
		case JIT_TYPE_SIGNATURE:
		case JIT_TYPE_PTR:
		case JIT_TYPE_LONG:
		case JIT_TYPE_ULONG:
		case JIT_TYPE_FLOAT32:
		case JIT_TYPE_FLOAT64:
		case JIT_TYPE_NFLOAT:
			if(!jit_insn_incoming_frame_posn(func, value, offset))
			{
				return 0;
			}
			--offset;
			break;

		case JIT_TYPE_STRUCT:
		case JIT_TYPE_UNION:
			if(!jit_insn_incoming_frame_posn(func, value, offset))
			{
				return 0;
			}
			offset -= JIT_NUM_ITEMS_IN_STRUCT(jit_type_get_size(type));
			break;
		}
	}
	return 1;
}