/*
* jit-type.c - Functions for manipulating type descriptors.
*
* 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
* .
*/
#include "jit-internal.h"
#include "jit-apply-rules.h"
#include "jit-rules.h"
/*@
@cindex jit-type.h
@tindex jit_type_t
The functions that are defined in @code{} allow
the library user to create and manipulate objects that represent
native system types. For example, @code{jit_type_int} represents
the signed 32-bit integer type.
Each @code{jit_type_t} object represents a basic system type,
be it a primitive, a struct, a union, a pointer, or a function signature.
The library uses this information to lay out values in memory.
The following pre-defined types are available:
@table @code
@vindex jit_type_void
@item jit_type_void
Represents the @code{void} type.
@vindex jit_type_sbyte
@item jit_type_sbyte
Represents a signed 8-bit integer type.
@vindex jit_type_ubyte
@item jit_type_ubyte
Represents an unsigned 8-bit integer type.
@vindex jit_type_short
@item jit_type_short
Represents a signed 16-bit integer type.
@vindex jit_type_ushort
@item jit_type_ushort
Represents an unsigned 16-bit integer type.
@vindex jit_type_int
@item jit_type_int
Represents a signed 32-bit integer type.
@vindex jit_type_uint
@item jit_type_uint
Represents an unsigned 32-bit integer type.
@vindex jit_type_nint
@item jit_type_nint
Represents a signed integer type that has the same size and
alignment as a native pointer.
@vindex jit_type_nuint
@item jit_type_nuint
Represents an unsigned integer type that has the same size and
alignment as a native pointer.
@vindex jit_type_long
@item jit_type_long
Represents a signed 64-bit integer type.
@vindex jit_type_ulong
@item jit_type_ulong
Represents an unsigned 64-bit integer type.
@vindex jit_type_float32
@item jit_type_float32
Represents a 32-bit floating point type.
@vindex jit_type_float64
@item jit_type_float64
Represents a 64-bit floating point type.
@vindex jit_type_nfloat
@item jit_type_nfloat
Represents a floating point type that represents the greatest
precision supported on the native platform.
@vindex jit_type_void_ptr
@item jit_type_void_ptr
Represents the system's @code{void *} type. This can be used wherever
a native pointer type is required.
@end table
Type descriptors are reference counted. You can make a copy of a type
descriptor using the @code{jit_type_copy} function, and free the copy with
@code{jit_type_free}.
Some languages have special versions of the primitive numeric types
(e.g. boolean types, 16-bit Unicode character types, enumerations, etc).
If it is important to distinguish these special versions from the
numeric types, then you should use the @code{jit_type_create_tagged}
function below.
The following types correspond to the system types on the local
platform. i.e. @code{jit_type_sys_int} will be the same size as
@code{long} on the local platform, whereas @code{jit_type_long} is
always 64 bits in size. These types should not be used to compile
code that is intended to work identically on all platforms:
@table @code
@vindex jit_type_sys_bool
@item jit_type_sys_bool
Corresponds to the system @code{bool} type.
@vindex jit_type_sys_char
@item jit_type_sys_char
Corresponds to the system @code{char} type. This may be either signed
or unsigned, depending upon the underlying system.
@vindex jit_type_sys_schar
@item jit_type_sys_schar
Corresponds to the system @code{signed char} type.
@vindex jit_type_sys_uchar
@item jit_type_sys_uchar
Corresponds to the system @code{unsigned char} type.
@vindex jit_type_sys_short
@item jit_type_sys_short
Corresponds to the system @code{short} type.
@vindex jit_type_sys_ushort
@item jit_type_sys_ushort
Corresponds to the system @code{unsigned short} type.
@vindex jit_type_sys_int
@item jit_type_sys_int
Corresponds to the system @code{int} type.
@vindex jit_type_sys_uint
@item jit_type_sys_uint
Corresponds to the system @code{unsigned int} type.
@vindex jit_type_sys_long
@item jit_type_sys_long
Corresponds to the system @code{long} type.
@vindex jit_type_sys_ulong
@item jit_type_sys_ulong
Corresponds to the system @code{unsigned long} type.
@vindex jit_type_sys_longlong
@item jit_type_sys_longlong
Corresponds to the system @code{long long} type (@code{__int64} under Win32).
@vindex jit_type_sys_ulonglong
@item jit_type_sys_ulonglong
Corresponds to the system @code{unsigned long long} type
(@code{unsigned __int64} under Win32).
@vindex jit_type_sys_float
@item jit_type_sys_float
Corresponds to the system @code{float} type.
@vindex jit_type_sys_double
@item jit_type_sys_double
Corresponds to the system @code{double} type.
@vindex jit_type_sys_long_double
@item jit_type_sys_long_double
Corresponds to the system @code{long double} type.
@end table
@*/
/*
* Pre-defined type descriptors.
*/
struct _jit_type const _jit_type_void_def =
{1, JIT_TYPE_VOID, 0, 1, 0, 1, 1};
jit_type_t const jit_type_void = (jit_type_t)&_jit_type_void_def;
struct _jit_type const _jit_type_sbyte_def =
{1, JIT_TYPE_SBYTE, 0, 1, 0, sizeof(jit_sbyte), JIT_ALIGN_SBYTE};
jit_type_t const jit_type_sbyte = (jit_type_t)&_jit_type_sbyte_def;
struct _jit_type const _jit_type_ubyte_def =
{1, JIT_TYPE_UBYTE, 0, 1, 0, sizeof(jit_ubyte), JIT_ALIGN_UBYTE};
jit_type_t const jit_type_ubyte = (jit_type_t)&_jit_type_ubyte_def;
struct _jit_type const _jit_type_short_def =
{1, JIT_TYPE_SHORT, 0, 1, 0, sizeof(jit_short), JIT_ALIGN_SHORT};
jit_type_t const jit_type_short = (jit_type_t)&_jit_type_short_def;
struct _jit_type const _jit_type_ushort_def =
{1, JIT_TYPE_USHORT, 0, 1, 0, sizeof(jit_ushort), JIT_ALIGN_USHORT};
jit_type_t const jit_type_ushort = (jit_type_t)&_jit_type_ushort_def;
struct _jit_type const _jit_type_int_def =
{1, JIT_TYPE_INT, 0, 1, 0, sizeof(jit_int), JIT_ALIGN_INT};
jit_type_t const jit_type_int = (jit_type_t)&_jit_type_int_def;
struct _jit_type const _jit_type_uint_def =
{1, JIT_TYPE_UINT, 0, 1, 0, sizeof(jit_uint), JIT_ALIGN_UINT};
jit_type_t const jit_type_uint = (jit_type_t)&_jit_type_uint_def;
struct _jit_type const _jit_type_nint_def =
{1, JIT_TYPE_NINT, 0, 1, 0, sizeof(jit_nint), JIT_ALIGN_NINT};
jit_type_t const jit_type_nint = (jit_type_t)&_jit_type_nint_def;
struct _jit_type const _jit_type_nuint_def =
{1, JIT_TYPE_NUINT, 0, 1, 0, sizeof(jit_nuint), JIT_ALIGN_NUINT};
jit_type_t const jit_type_nuint = (jit_type_t)&_jit_type_nuint_def;
struct _jit_type const _jit_type_long_def =
{1, JIT_TYPE_LONG, 0, 1, 0, sizeof(jit_long), JIT_ALIGN_LONG};
jit_type_t const jit_type_long = (jit_type_t)&_jit_type_long_def;
struct _jit_type const _jit_type_ulong_def =
{1, JIT_TYPE_ULONG, 0, 1, 0, sizeof(jit_ulong), JIT_ALIGN_ULONG};
jit_type_t const jit_type_ulong = (jit_type_t)&_jit_type_ulong_def;
struct _jit_type const _jit_type_float32_def =
{1, JIT_TYPE_FLOAT32, 0, 1, 0, sizeof(jit_float32), JIT_ALIGN_FLOAT32};
jit_type_t const jit_type_float32 = (jit_type_t)&_jit_type_float32_def;
struct _jit_type const _jit_type_float64_def =
{1, JIT_TYPE_FLOAT64, 0, 1, 0, sizeof(jit_float64), JIT_ALIGN_FLOAT64};
jit_type_t const jit_type_float64 = (jit_type_t)&_jit_type_float64_def;
struct _jit_type const _jit_type_nfloat_def =
{1, JIT_TYPE_NFLOAT, 0, 1, 0, sizeof(jit_nfloat), JIT_ALIGN_NFLOAT};
jit_type_t const jit_type_nfloat = (jit_type_t)&_jit_type_nfloat_def;
struct _jit_type const _jit_type_void_ptr_def =
{1, JIT_TYPE_PTR, 0, 1, 0, sizeof(void *), JIT_ALIGN_PTR,
(jit_type_t)&_jit_type_void_def};
jit_type_t const jit_type_void_ptr = (jit_type_t)&_jit_type_void_ptr_def;
/*
* Type descriptors for the system "char", "int", "long", etc types.
* These are defined to one of the above values, tagged with a value
* that indicates which system type it is referring to.
*/
#define DECLARE_TAGGED(name,real,tag) \
static struct jit_tagged_type const name##_tagged = \
{{1, JIT_TYPE_FIRST_TAGGED + (tag), 0, 1, 0, 0, 0, \
(jit_type_t)&_jit_type_##real}, 0, 0}; \
jit_type_t const jit_type_##name = (jit_type_t)&name##_tagged
DECLARE_TAGGED(sys_bool, ubyte_def, JIT_TYPETAG_SYS_BOOL);
#ifdef __CHAR_UNSIGNED__
DECLARE_TAGGED(sys_char, ubyte_def, JIT_TYPETAG_SYS_CHAR);
#else
DECLARE_TAGGED(sys_char, sbyte_def, JIT_TYPETAG_SYS_CHAR);
#endif
DECLARE_TAGGED(sys_schar, sbyte_def, JIT_TYPETAG_SYS_SCHAR);
DECLARE_TAGGED(sys_uchar, ubyte_def, JIT_TYPETAG_SYS_UCHAR);
#if SIZEOF_SHORT == 4
DECLARE_TAGGED(sys_short, int_def, JIT_TYPETAG_SYS_SHORT);
DECLARE_TAGGED(sys_ushort, uint_def, JIT_TYPETAG_SYS_USHORT);
#elif SIZEOF_SHORT == 8
DECLARE_TAGGED(sys_short, long_def, JIT_TYPETAG_SYS_SHORT);
DECLARE_TAGGED(sys_ushort, ulong_def, JIT_TYPETAG_SYS_USHORT);
#else
DECLARE_TAGGED(sys_short, short_def, JIT_TYPETAG_SYS_SHORT);
DECLARE_TAGGED(sys_ushort, ushort_def, JIT_TYPETAG_SYS_USHORT);
#endif
#if SIZEOF_INT == 8
DECLARE_TAGGED(sys_int, long_def, JIT_TYPETAG_SYS_INT);
DECLARE_TAGGED(sys_uint, ulong_def, JIT_TYPETAG_SYS_UINT);
#elif SIZEOF_INT == 2
DECLARE_TAGGED(sys_int, short_def, JIT_TYPETAG_SYS_INT);
DECLARE_TAGGED(sys_uint, ushort_def, JIT_TYPETAG_SYS_UINT);
#else
DECLARE_TAGGED(sys_int, int_def, JIT_TYPETAG_SYS_INT);
DECLARE_TAGGED(sys_uint, uint_def, JIT_TYPETAG_SYS_UINT);
#endif
#if SIZEOF_LONG == 8
DECLARE_TAGGED(sys_long, long_def, JIT_TYPETAG_SYS_LONG);
DECLARE_TAGGED(sys_ulong, ulong_def, JIT_TYPETAG_SYS_ULONG);
#elif SIZEOF_LONG == 2
DECLARE_TAGGED(sys_long, short_def, JIT_TYPETAG_SYS_LONG);
DECLARE_TAGGED(sys_ulong, ushort_def, JIT_TYPETAG_SYS_ULONG);
#else
DECLARE_TAGGED(sys_long, int_def, JIT_TYPETAG_SYS_LONG);
DECLARE_TAGGED(sys_ulong, uint_def, JIT_TYPETAG_SYS_ULONG);
#endif
#if SIZEOF_LONG_LONG == 8 || SIZEOF___INT64 == 8
DECLARE_TAGGED(sys_longlong, long_def, JIT_TYPETAG_SYS_LONGLONG);
DECLARE_TAGGED(sys_ulonglong, ulong_def, JIT_TYPETAG_SYS_ULONGLONG);
#elif SIZEOF_LONG_LONG == 4
DECLARE_TAGGED(sys_longlong, int_def, JIT_TYPETAG_SYS_LONGLONG);
DECLARE_TAGGED(sys_ulonglong, uint_def, JIT_TYPETAG_SYS_ULONGLONG);
#elif SIZEOF_LONG_LONG == 2
DECLARE_TAGGED(sys_longlong, short_def, JIT_TYPETAG_SYS_LONGLONG);
DECLARE_TAGGED(sys_ulonglong, ushort_def, JIT_TYPETAG_SYS_ULONGLONG);
#else
DECLARE_TAGGED(sys_longlong, long_def, JIT_TYPETAG_SYS_LONGLONG);
DECLARE_TAGGED(sys_ulonglong, ulong_def, JIT_TYPETAG_SYS_ULONGLONG);
#endif
DECLARE_TAGGED(sys_float, float32_def, JIT_TYPETAG_SYS_FLOAT);
DECLARE_TAGGED(sys_double, float64_def, JIT_TYPETAG_SYS_DOUBLE);
DECLARE_TAGGED(sys_long_double, nfloat_def, JIT_TYPETAG_SYS_LONGDOUBLE);
/*
* Special offset flags.
*/
#define JIT_OFFSET_IS_INTERNAL (((jit_nuint)1) << (sizeof(jit_nint) * 8 - 1))
#define JIT_OFFSET_NOT_SET (~((jit_nuint)0))
/*
* Layout flags.
*/
#define JIT_LAYOUT_NEEDED 1
#define JIT_LAYOUT_EXPLICIT_SIZE 2
#define JIT_LAYOUT_EXPLICIT_ALIGN 4
/*
* Perform layout on a structure or union type.
*/
static void perform_layout(jit_type_t type)
{
jit_nuint size = 0;
jit_nuint maxSize = 0;
jit_nuint maxAlign = 1;
jit_nuint alignLimit;
jit_nuint fieldSize;
jit_nuint fieldAlign;
unsigned int index;
/* Determine the alignment limit, if there is an override */
#ifdef JIT_ALIGN_OVERRIDES
if((type->layout_flags & JIT_LAYOUT_EXPLICIT_ALIGN) != 0)
{
alignLimit = type->alignment;
}
else
#endif
{
alignLimit = 0;
}
/* Lay out all of the fields in this structure */
for(index = 0; index < type->num_components; ++index)
{
/* Get the size and alignment of the field */
fieldSize = jit_type_get_size(type->components[index].type);
fieldAlign = jit_type_get_alignment(type->components[index].type);
/* Clamp the alignment if we have a limit */
if(alignLimit != 0 && fieldAlign > alignLimit)
{
fieldAlign = alignLimit;
}
/* Update the size and alignment values */
if(type->kind == JIT_TYPE_STRUCT)
{
/* Perform layout for a struct type */
if((type->components[index].offset & JIT_OFFSET_IS_INTERNAL) != 0)
{
/* Calculate the offset for the field automatically */
if((size % fieldAlign) != 0)
{
size += fieldAlign - (size % fieldAlign);
}
type->components[index].offset = JIT_OFFSET_IS_INTERNAL | size;
size += fieldSize;
}
else
{
/* Use the explicitly-supplied offset for the field */
size = type->components[index].offset + fieldSize;
}
if(size > maxSize)
{
maxSize = size;
}
}
else
{
/* Perform layout for a union type (offset is always zero) */
type->components[index].offset = JIT_OFFSET_IS_INTERNAL | 0;
if((fieldSize % fieldAlign) != 0)
{
fieldSize += fieldAlign - (fieldSize % fieldAlign);
}
if(fieldSize > maxSize)
{
maxSize = fieldSize;
}
}
if(fieldAlign > maxAlign)
{
maxAlign = fieldAlign;
}
}
/* Align the full structure */
if((maxSize % maxAlign) != 0)
{
maxSize += maxAlign - (maxSize % maxAlign);
}
/* Record the final size and alignment values */
if((type->layout_flags & JIT_LAYOUT_EXPLICIT_SIZE) != 0)
{
if(maxSize > type->size)
{
type->size = maxSize;
}
}
else
{
type->size = maxSize;
}
if(maxAlign > type->alignment)
{
type->alignment = maxAlign;
}
}
/*@
* @deftypefun jit_type_t jit_type_copy (jit_type_t @var{type})
* Make a copy of the type descriptor @var{type} by increasing
* its reference count.
* @end deftypefun
@*/
jit_type_t jit_type_copy(jit_type_t type)
{
if(!type || type->is_fixed)
{
return type;
}
++(type->ref_count);
return type;
}
/*@
* @deftypefun void jit_type_free (jit_type_t @var{type})
* Free a type descriptor by decreasing its reference count.
* This function is safe to use on pre-defined types, which are
* never actually freed.
* @end deftypefun
@*/
void jit_type_free(jit_type_t type)
{
unsigned int index;
if(!type || type->is_fixed)
{
return;
}
if(--(type->ref_count) != 0)
{
return;
}
jit_type_free(type->sub_type);
for(index = 0; index < type->num_components; ++index)
{
jit_type_free(type->components[index].type);
if(type->components[index].name)
{
jit_free(type->components[index].name);
}
}
if(type->kind >= JIT_TYPE_FIRST_TAGGED)
{
struct jit_tagged_type *tagged = (struct jit_tagged_type *)type;
if(tagged->free_func)
{
(*(tagged->free_func))(tagged->data);
}
}
jit_free(type);
}
static jit_type_t create_complex(int kind, jit_type_t *types,
unsigned int num, int incref)
{
jit_type_t type;
unsigned int index;
if(num <= 1)
{
type = jit_cnew(struct _jit_type);
}
else
{
type = (jit_type_t)jit_calloc
(1, sizeof(struct _jit_type) +
(num - 1) * sizeof(struct jit_component));
}
if(!type)
{
return 0;
}
type->ref_count = 1;
type->kind = kind;
type->layout_flags = JIT_LAYOUT_NEEDED;
type->num_components = num;
for(index = 0; index < num; ++index)
{
if(incref)
{
type->components[index].type = jit_type_copy(types[index]);
}
else
{
type->components[index].type = types[index];
}
type->components[index].offset = JIT_OFFSET_NOT_SET;
type->components[index].name = 0;
}
return type;
}
/*@
* @deftypefun jit_type_t jit_type_create_struct (jit_type_t *@var{fields}, unsigned int @var{num_fields}, int @var{incref})
* Create a type descriptor for a structure. Returns NULL if out of memory.
* If there are no fields, then the size of the structure will be zero.
* It is necessary to add a padding field if the language does not allow
* zero-sized structures. The reference counts on the field types are
* incremented if @var{incref} is non-zero.
*
* The @code{libjit} library does not provide any special support for
* implementing structure inheritance, where one structure extends the
* definition of another. The effect of inheritance can be achieved
* by always allocating the first field of a structure to be an instance
* of the inherited structure. Multiple inheritance can be supported
* by allocating several special fields at the front of an inheriting
* structure.
*
* Similarly, no special support is provided for vtables. The program
* is responsible for allocating an appropriate slot in a structure to
* contain the vtable pointer, and dereferencing it wherever necessary.
* The vtable will itself be a structure, containing signature types
* for each of the method slots.
*
* The choice not to provide special support for inheritance and vtables
* in @code{libjit} was deliberate. The layout of objects and vtables
* is highly specific to the language and virtual machine being emulated,
* and no single scheme can hope to capture all possibilities.
* @end deftypefun
@*/
jit_type_t jit_type_create_struct(jit_type_t *fields, unsigned int num_fields,
int incref)
{
return create_complex(JIT_TYPE_STRUCT, fields, num_fields, incref);
}
/*@
* @deftypefun jit_type_t jit_type_create_union (jit_type_t *@var{fields}, unsigned int @var{num_fields}, int @var{incref})
* Create a type descriptor for a union. Returns NULL if out of memory.
* If there are no fields, then the size of the union will be zero.
* It is necessary to add a padding field if the language does not allow
* zero-sized unions. The reference counts on the field types are
* incremented if @var{incref} is non-zero.
* @end deftypefun
@*/
jit_type_t jit_type_create_union(jit_type_t *fields, unsigned int num_fields,
int incref)
{
return create_complex(JIT_TYPE_UNION, fields, num_fields, incref);
}
/*@
* @deftypefun jit_type_t jit_type_create_signature (jit_abi_t @var{abi}, jit_type_t @var{return_type}, jit_type_t *@var{params}, unsigned int @var{num_params}, int @var{incref})
* Create a type descriptor for a function signature. Returns NULL if out
* of memory. The reference counts on the component types are incremented
* if @var{incref} is non-zero.
*
* When used as a structure or union field, function signatures are laid
* out like pointers. That is, they represent a pointer to a function
* that has the specified parameters and return type.
*
* @tindex jit_abi_t
* The @var{abi} parameter specifies the Application Binary Interface (ABI)
* that the function uses. It may be one of the following values:
*
* @table @code
* @vindex jit_abi_cdecl
* @item jit_abi_cdecl
* Use the native C ABI definitions of the underlying platform.
*
* @vindex jit_abi_vararg
* @item jit_abi_vararg
* Use the native C ABI definitions of the underlying platform,
* and allow for an optional list of variable argument parameters.
*
* @vindex jit_abi_stdcall
* @item jit_abi_stdcall
* Use the Win32 STDCALL ABI definitions, whereby the callee pops
* its arguments rather than the caller. If the platform does
* not support this type of ABI, then @code{jit_abi_stdcall} will be
* identical to @code{jit_abi_cdecl}.
*
* @vindex jit_abi_fastcall
* @item jit_abi_fastcall
* Use the Win32 FASTCALL ABI definitions, whereby the callee pops
* its arguments rather than the caller, and the first two word
* arguments are passed in ECX and EDX. If the platform does
* not support this type of ABI, then @code{jit_abi_fastcall} will be
* identical to @code{jit_abi_cdecl}.
* @end table
* @end deftypefun
@*/
jit_type_t jit_type_create_signature(jit_abi_t abi, jit_type_t return_type,
jit_type_t *params,
unsigned int num_params, int incref)
{
jit_type_t type;
type = create_complex(JIT_TYPE_SIGNATURE, params, num_params, incref);
if(type)
{
type->abi = (int)abi;
type->layout_flags = 0;
type->size = 0;
type->alignment = JIT_ALIGN_PTR;
if(incref)
{
type->sub_type = jit_type_copy(return_type);
}
else
{
type->sub_type = return_type;
}
}
return type;
}
/*@
* @deftypefun jit_type_t jit_type_create_pointer (jit_type_t @var{type}, int @var{incref})
* Create a type descriptor for a pointer to another type. Returns NULL
* if out of memory. The reference count on @var{type} is incremented if
* @var{incref} is non-zero.
* @end deftypefun
@*/
jit_type_t jit_type_create_pointer(jit_type_t type, int incref)
{
jit_type_t ntype;
if(type == jit_type_void)
{
return jit_type_void_ptr;
}
if((ntype = jit_cnew(struct _jit_type)) == 0)
{
return 0;
}
ntype->ref_count = 1;
ntype->kind = JIT_TYPE_PTR;
ntype->size = sizeof(void *);
ntype->alignment = JIT_ALIGN_PTR;
if(incref)
{
ntype->sub_type = jit_type_copy(type);
}
else
{
ntype->sub_type = type;
}
return ntype;
}
/*@
* @deftypefun jit_type_t jit_type_create_tagged (jit_type_t @var{type}, int @var{kind}, void *@var{data}, jit_meta_free_func @var{free_func}, int @var{incref})
* Tag a type with some additional user data. Tagging is typically used by
* higher-level programs to embed extra information about a type that
* @code{libjit} itself does not support.
*
* As an example, a language might have a 16-bit Unicode character type
* and a 16-bit unsigned integer type that are distinct types, even though
* they share the same fundamental representation (@code{jit_ushort}).
* Tagging allows the program to distinguish these two types, when
* it is necessary to do so, without affecting @code{libjit}'s ability
* to compile the code efficiently.
*
* The @var{kind} is a small positive integer value that the program
* can use to distinguish multiple tag types. The @var{data} pointer is
* the actual data that you wish to store. And @var{free_func} is a
* function that is used to free @var{data} when the type is freed
* with @code{jit_type_free}.
*
* If you need to store more than one piece of information, you can
* tag a type multiple times. The order in which multiple tags are
* applied is irrelevant to @code{libjit}, although it may be relevant
* to the higher-level program.
*
* Tag kinds of 10000 or greater are reserved for @code{libjit} itself.
* The following special tag kinds are currently provided in the
* base implementation:
*
* @table @code
* @vindex JIT_TYPETAG_NAME
* @item JIT_TYPETAG_NAME
* The @var{data} pointer is a @code{char *} string indicating a friendly
* name to display for the type.
*
* @vindex JIT_TYPETAG_STRUCT_NAME
* @vindex JIT_TYPETAG_UNION_NAME
* @vindex JIT_TYPETAG_ENUM_NAME
* @item JIT_TYPETAG_STRUCT_NAME
* @itemx JIT_TYPETAG_UNION_NAME
* @itemx JIT_TYPETAG_ENUM_NAME
* The @var{data} pointer is a @code{char *} string indicating a friendly
* name to display for a @code{struct}, @code{union}, or @code{enum} type.
* This is for languages like C that have separate naming scopes for
* typedef's and structures.
*
* @vindex JIT_TYPETAG_CONST
* @item JIT_TYPETAG_CONST
* The underlying value is assumed to have @code{const} semantics.
* The @code{libjit} library doesn't enforce such semantics: it is
* up to the front-end to only use constant values in appopriate contexts.
*
* @vindex JIT_TYPETAG_VOLATILE
* @item JIT_TYPETAG_VOLATILE
* The underlying value is assumed to be volatile. The @code{libjit}
* library will automatically call @code{jit_value_set_volatile} when a
* value is constructed using this type.
*
* @vindex JIT_TYPETAG_REFERENCE
* @item JIT_TYPETAG_REFERENCE
* The underlying value is a pointer, but it is assumed to refer to a
* pass-by-reference parameter.
*
* @vindex JIT_TYPETAG_OUTPUT
* @item JIT_TYPETAG_OUTPUT
* This is similar to @code{JIT_TYPETAG_REFERENCE}, except that the
* underlying parameter is assumed to be output-only.
*
* @vindex JIT_TYPETAG_RESTRICT
* @item JIT_TYPETAG_RESTRICT
* The underlying type is marked as @code{restrict}. Normally ignored.
*
* @vindex JIT_TYPETAG_SYS_BOOL
* @vindex JIT_TYPETAG_SYS_CHAR
* @vindex JIT_TYPETAG_SYS_SCHAR
* @vindex JIT_TYPETAG_SYS_UCHAR
* @vindex JIT_TYPETAG_SYS_SHORT
* @vindex JIT_TYPETAG_SYS_USHORT
* @vindex JIT_TYPETAG_SYS_INT
* @vindex JIT_TYPETAG_SYS_UINT
* @vindex JIT_TYPETAG_SYS_LONG
* @vindex JIT_TYPETAG_SYS_ULONG
* @vindex JIT_TYPETAG_SYS_LONGLONG
* @vindex JIT_TYPETAG_SYS_ULONGLONG
* @vindex JIT_TYPETAG_SYS_FLOAT
* @vindex JIT_TYPETAG_SYS_DOUBLE
* @vindex JIT_TYPETAG_SYS_LONGDOUBLE
* @item JIT_TYPETAG_SYS_BOOL
* @itemx JIT_TYPETAG_SYS_CHAR
* @itemx JIT_TYPETAG_SYS_SCHAR
* @itemx JIT_TYPETAG_SYS_UCHAR
* @itemx JIT_TYPETAG_SYS_SHORT
* @itemx JIT_TYPETAG_SYS_USHORT
* @itemx JIT_TYPETAG_SYS_INT
* @itemx JIT_TYPETAG_SYS_UINT
* @itemx JIT_TYPETAG_SYS_LONG
* @itemx JIT_TYPETAG_SYS_ULONG
* @itemx JIT_TYPETAG_SYS_LONGLONG
* @itemx JIT_TYPETAG_SYS_ULONGLONG
* @itemx JIT_TYPETAG_SYS_FLOAT
* @itemx JIT_TYPETAG_SYS_DOUBLE
* @itemx JIT_TYPETAG_SYS_LONGDOUBLE
* Used to mark types that we know for a fact correspond to the system
* C types of the corresponding names. This is primarily used to distinguish
* system types like @code{int} and @code{long} types on 32-bit platforms
* when it is necessary to do so. The @code{jit_type_sys_xxx} values are
* all tagged in this manner.
* @end table
* @end deftypefun
@*/
jit_type_t jit_type_create_tagged(jit_type_t type, int kind, void *data,
jit_meta_free_func free_func, int incref)
{
struct jit_tagged_type *ntype;
if((ntype = jit_cnew(struct jit_tagged_type)) == 0)
{
return 0;
}
ntype->type.ref_count = 1;
ntype->type.kind = JIT_TYPE_FIRST_TAGGED + kind;
ntype->type.size = 0;
ntype->type.alignment = 1;
if(incref)
{
ntype->type.sub_type = jit_type_copy(type);
}
else
{
ntype->type.sub_type = type;
}
ntype->data = data;
ntype->free_func = free_func;
return &(ntype->type);
}
/*@
* @deftypefun int jit_type_set_names (jit_type_t @var{type}, char **@var{names}, unsigned int @var{num_names})
* Set the field or parameter names for @var{type}. Returns zero
* if there is insufficient memory to set the names.
*
* Normally fields are accessed via their index. Field names are a
* convenience for front ends that prefer to use names to indices.
* @end deftypefun
@*/
int jit_type_set_names(jit_type_t type, char **names, unsigned int num_names)
{
char *temp;
if(!type || type->is_fixed || !names)
{
return 1;
}
if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION ||
type->kind == JIT_TYPE_SIGNATURE)
{
if(num_names > type->num_components)
{
num_names = type->num_components;
}
while(num_names > 0)
{
--num_names;
if(type->components[num_names].name)
{
jit_free(type->components[num_names].name);
type->components[num_names].name = 0;
}
if(names[num_names])
{
temp = jit_strdup(names[num_names]);
if(!temp)
{
return 0;
}
type->components[num_names].name = temp;
}
}
}
return 1;
}
/*@
* @deftypefun void jit_type_set_size_and_alignment (jit_type_t @var{type}, jit_nint @var{size}, jit_nint @var{alignment})
* Set the size and alignment information for a structure or union
* type. Use this for performing explicit type layout. Normally
* the size is computed automatically. Ignored if not a
* structure or union type. Setting either value to -1 will cause
* that value to be computed automatically.
* @end deftypefun
@*/
void jit_type_set_size_and_alignment(jit_type_t type, jit_nint size,
jit_nint alignment)
{
if(!type)
{
return;
}
if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
{
type->size = (jit_nuint)size;
type->alignment = (jit_nuint)alignment;
if(size != -1)
{
type->layout_flags |= JIT_LAYOUT_EXPLICIT_SIZE;
}
if(alignment != -1)
{
type->layout_flags |= JIT_LAYOUT_EXPLICIT_ALIGN;
}
type->layout_flags |= JIT_LAYOUT_NEEDED;
}
}
/*@
* @deftypefun void jit_type_set_offset (jit_type_t @var{type}, unsigned int @var{field_index}, jit_nuint @var{offset})
* Set the offset of a specific structure field. Use this for
* performing explicit type layout. Normally the offset is
* computed automatically. Ignored if not a structure type,
* or the field index is out of range.
* @end deftypefun
@*/
void jit_type_set_offset(jit_type_t type, unsigned int field_index,
jit_nuint offset)
{
if(!type || field_index >= type->num_components)
{
return;
}
if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
{
type->components[field_index].offset = offset;
type->layout_flags |= JIT_LAYOUT_NEEDED;
}
}
/*@
* @deftypefun int jit_type_get_kind (jit_type_t @var{type})
* Get a value that indicates the kind of @var{type}. This allows
* callers to quickly classify a type to determine how it should be
* handled further.
*
* @table @code
* @vindex JIT_TYPE_INVALID
* @item JIT_TYPE_INVALID
* The value of the @var{type} parameter is NULL.
*
* @vindex JIT_TYPE_VOID
* @item JIT_TYPE_VOID
* The type is @code{jit_type_void}.
*
* @vindex JIT_TYPE_SBYTE
* @item JIT_TYPE_SBYTE
* The type is @code{jit_type_sbyte}.
*
* @vindex JIT_TYPE_UBYTE
* @item JIT_TYPE_UBYTE
* The type is @code{jit_type_ubyte}.
*
* @vindex JIT_TYPE_SHORT
* @item JIT_TYPE_SHORT
* The type is @code{jit_type_short}.
*
* @vindex JIT_TYPE_USHORT
* @item JIT_TYPE_USHORT
* The type is @code{jit_type_ushort}.
*
* @vindex JIT_TYPE_INT
* @item JIT_TYPE_INT
* The type is @code{jit_type_int}.
*
* @vindex JIT_TYPE_UINT
* @item JIT_TYPE_UINT
* The type is @code{jit_type_uint}.
*
* @vindex JIT_TYPE_NINT
* @item JIT_TYPE_NINT
* The type is @code{jit_type_nint}.
*
* @vindex JIT_TYPE_NUINT
* @item JIT_TYPE_NUINT
* The type is @code{jit_type_nuint}.
*
* @vindex JIT_TYPE_LONG
* @item JIT_TYPE_LONG
* The type is @code{jit_type_long}.
*
* @vindex JIT_TYPE_ULONG
* @item JIT_TYPE_ULONG
* The type is @code{jit_type_ulong}.
*
* @vindex JIT_TYPE_FLOAT32
* @item JIT_TYPE_FLOAT32
* The type is @code{jit_type_float32}.
*
* @vindex JIT_TYPE_FLOAT64
* @item JIT_TYPE_FLOAT64
* The type is @code{jit_type_float64}.
*
* @vindex JIT_TYPE_NFLOAT
* @item JIT_TYPE_NFLOAT
* The type is @code{jit_type_nfloat}.
*
* @vindex JIT_TYPE_STRUCT
* @item JIT_TYPE_STRUCT
* The type is the result of calling @code{jit_type_create_struct}.
*
* @vindex JIT_TYPE_UNION
* @item JIT_TYPE_UNION
* The type is the result of calling @code{jit_type_create_union}.
*
* @vindex JIT_TYPE_SIGNATURE
* @item JIT_TYPE_SIGNATURE
* The type is the result of calling @code{jit_type_create_signature}.
*
* @vindex JIT_TYPE_PTR
* @item JIT_TYPE_PTR
* The type is the result of calling @code{jit_type_create_pointer}.
* @end table
*
* @vindex JIT_TYPE_FIRST_TAGGED
* If this function returns @code{JIT_TYPE_FIRST_TAGGED} or higher,
* then the type is tagged and its tag kind is the return value minus
* @code{JIT_TYPE_FIRST_TAGGED}. That is, the following two expressions
* will be identical if @var{type} is tagged:
*
* @example
* jit_type_get_tagged_kind(type)
* jit_type_get_kind(type) - JIT_TYPE_FIRST_TAGGED
* @end example
* @end deftypefun
@*/
int jit_type_get_kind(jit_type_t type)
{
if(!type)
{
return JIT_TYPE_INVALID;
}
else
{
return type->kind;
}
}
/*@
* @deftypefun jit_nuint jit_type_get_size (jit_type_t @var{type})
* Get the size of a type in bytes.
* @end deftypefun
@*/
jit_nuint jit_type_get_size(jit_type_t type)
{
if(!type)
{
return 0;
}
if(type->kind == JIT_TYPE_SIGNATURE)
{
/* The "size" field is used for argument size, not type size,
so we ignore it and return the real size here */
return sizeof(void *);
}
else if(type->kind >= JIT_TYPE_FIRST_TAGGED)
{
return jit_type_get_size(type->sub_type);
}
if((type->layout_flags & JIT_LAYOUT_NEEDED) != 0)
{
perform_layout(type);
}
return type->size;
}
/*@
* @deftypefun jit_nuint jit_type_get_alignment (jit_type_t @var{type})
* Get the alignment of a type. An alignment value of 2 indicates
* that the type should be aligned on a two-byte boundary, for example.
* @end deftypefun
@*/
jit_nuint jit_type_get_alignment(jit_type_t type)
{
if(!type)
{
return 0;
}
if(type->kind >= JIT_TYPE_FIRST_TAGGED)
{
return jit_type_get_alignment(type->sub_type);
}
if((type->layout_flags & JIT_LAYOUT_NEEDED) != 0)
{
perform_layout(type);
}
return type->alignment;
}
/*@
* @deftypefun {unsigned int} jit_type_num_fields (jit_type_t @var{type})
* Get the number of fields in a structure or union type.
* @end deftypefun
@*/
unsigned int jit_type_num_fields(jit_type_t type)
{
if(!type ||
(type->kind != JIT_TYPE_STRUCT && type->kind != JIT_TYPE_UNION))
{
return 0;
}
else
{
return type->num_components;
}
}
/*@
* @deftypefun jit_type_t jit_type_get_field (jit_type_t @var{type}, unsigned int @var{field_index})
* Get the type of a specific field within a structure or union.
* Returns NULL if not a structure or union, or the index is out of range.
* @end deftypefun
@*/
jit_type_t jit_type_get_field(jit_type_t type, unsigned int field_index)
{
if(!type || field_index >= type->num_components)
{
return 0;
}
if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
{
return type->components[field_index].type;
}
return 0;
}
/*@
* @deftypefun jit_nuint jit_type_get_offset (jit_type_t @var{type}, unsigned int @var{field_index})
* Get the offset of a specific field within a structure.
* Returns zero if not a structure, or the index is out of range,
* so this is safe to use on non-structure types.
* @end deftypefun
@*/
jit_nuint jit_type_get_offset(jit_type_t type, unsigned int field_index)
{
if(!type || field_index >= type->num_components)
{
return 0;
}
if(type->kind != JIT_TYPE_STRUCT && type->kind != JIT_TYPE_UNION)
{
return 0;
}
if((type->layout_flags & JIT_LAYOUT_NEEDED) != 0)
{
perform_layout(type);
}
return type->components[field_index].offset & ~JIT_OFFSET_IS_INTERNAL;
}
/*@
* @deftypefun {const char *} jit_type_get_name (jit_type_t @var{type}, unsigned int @var{index})
* Get the name of a structure, union, or signature field/parameter.
* Returns NULL if not a structure, union, or signature, the index
* is out of range, or there is no name associated with the component.
* @end deftypefun
@*/
const char *jit_type_get_name(jit_type_t type, unsigned int index)
{
if(!type || index >= type->num_components)
{
return 0;
}
else
{
return type->components[index].name;
}
}
/*@
* @deftypefun {unsigned int} jit_type_find_name (jit_type_t @var{type}, const char *@var{name})
* Find the field/parameter index for a particular name. Returns
* @code{JIT_INVALID_NAME} if the name was not present.
* @end deftypefun
@*/
unsigned int jit_type_find_name(jit_type_t type, const char *name)
{
unsigned int index;
if(!type || !name)
{
return JIT_INVALID_NAME;
}
if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION ||
type->kind == JIT_TYPE_SIGNATURE)
{
for(index = 0; index < type->num_components; ++index)
{
if(type->components[index].name &&
!jit_strcmp(type->components[index].name, name))
{
return index;
}
}
}
return JIT_INVALID_NAME;
}
/*@
* @deftypefun {unsigned int} jit_type_num_params (jit_type_t @var{type})
* Get the number of parameters in a signature type.
* @end deftypefun
@*/
unsigned int jit_type_num_params(jit_type_t type)
{
if(!type || type->kind != JIT_TYPE_SIGNATURE)
{
return 0;
}
else
{
return type->num_components;
}
}
/*@
* @deftypefun jit_type_t jit_type_get_return (jit_type_t @var{type})
* Get the return type from a signature type. Returns NULL if
* not a signature type.
* @end deftypefun
@*/
jit_type_t jit_type_get_return(jit_type_t type)
{
if(type)
{
if(type->kind == JIT_TYPE_SIGNATURE)
{
return type->sub_type;
}
}
return 0;
}
/*@
* @deftypefun jit_type_t jit_type_get_param (jit_type_t @var{type}, unsigned int @var{param_index})
* Get a specific parameter from a signature type. Returns NULL
* if not a signature type or the index is out of range.
* @end deftypefun
@*/
jit_type_t jit_type_get_param(jit_type_t type, unsigned int param_index)
{
if(!type || param_index >= type->num_components)
{
return 0;
}
if(type->kind == JIT_TYPE_SIGNATURE)
{
return type->components[param_index].type;
}
return 0;
}
/*@
* @deftypefun jit_abi_t jit_type_get_abi (jit_type_t @var{type})
* Get the ABI code from a signature type. Returns @code{jit_abi_cdecl}
* if not a signature type.
* @end deftypefun
@*/
jit_abi_t jit_type_get_abi(jit_type_t type)
{
if(type)
{
return (jit_abi_t)(type->abi);
}
else
{
return jit_abi_cdecl;
}
}
/*@
* @deftypefun jit_type_t jit_type_get_ref (jit_type_t @var{type})
* Get the type that is referred to by a pointer type. Returns NULL
* if not a pointer type.
* @end deftypefun
@*/
jit_type_t jit_type_get_ref(jit_type_t type)
{
if(type)
{
if(type->kind == JIT_TYPE_PTR)
{
return type->sub_type;
}
}
return 0;
}
/*@
* @deftypefun jit_type_t jit_type_get_tagged_type (jit_type_t @var{type})
* Get the type that underlies a tagged type. Returns NULL
* if not a tagged type.
* @end deftypefun
@*/
jit_type_t jit_type_get_tagged_type(jit_type_t type)
{
if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
{
return type->sub_type;
}
else
{
return 0;
}
}
/*@
* @deftypefun void jit_type_set_tagged_type (jit_type_t @var{type}, jit_type_t @var{underlying}, int @var{incref})
* Set the type that underlies a tagged type. Ignored if @var{type}
* is not a tagged type. If @var{type} already has an underlying
* type, then the original is freed. The reference count on @var{underlying}
* is incremented if @var{incref} is non-zero.
*
* This function is typically used to flesh out the body of a
* forward-declared type. The tag is used as a placeholder
* until the definition can be located.
* @end deftypefun
@*/
void jit_type_set_tagged_type(jit_type_t type, jit_type_t underlying,
int incref)
{
if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
{
if(type->sub_type != underlying)
{
jit_type_free(type->sub_type);
if(incref)
{
type->sub_type = jit_type_copy(underlying);
}
else
{
type->sub_type = underlying;
}
}
}
}
/*@
* @deftypefun int jit_type_get_tagged_kind (jit_type_t @var{type})
* Get the kind of tag that is applied to a tagged type. Returns -1
* if not a tagged type.
* @end deftypefun
@*/
int jit_type_get_tagged_kind(jit_type_t type)
{
if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
{
return type->kind - JIT_TYPE_FIRST_TAGGED;
}
else
{
return -1;
}
}
/*@
* @deftypefun {void *} jit_type_get_tagged_data (jit_type_t @var{type})
* Get the user data is associated with a tagged type. Returns NULL
* if not a tagged type.
* @end deftypefun
@*/
void *jit_type_get_tagged_data(jit_type_t type)
{
if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
{
return ((struct jit_tagged_type *)type)->data;
}
else
{
return 0;
}
}
/*@
* @deftypefun void jit_type_set_tagged_data (jit_type_t @var{type}, void *@var{data}, jit_meta_free_func @var{free_func})
* Set the user data is associated with a tagged type. The original data,
* if any, is freed.
* @end deftypefun
@*/
void jit_type_set_tagged_data(jit_type_t type, void *data,
jit_meta_free_func free_func)
{
if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
{
struct jit_tagged_type *tagged = (struct jit_tagged_type *)type;
if(tagged->data != data)
{
if(tagged->free_func)
{
(*(tagged->free_func))(tagged->data);
}
tagged->data = data;
tagged->free_func = free_func;
}
}
}
/*@
* @deftypefun int jit_type_is_primitive (jit_type_t @var{type})
* Determine if a type is primitive.
* @end deftypefun
@*/
int jit_type_is_primitive(jit_type_t type)
{
if(type)
{
return (type->kind <= JIT_TYPE_MAX_PRIMITIVE);
}
else
{
return 0;
}
}
/*@
* @deftypefun int jit_type_is_struct (jit_type_t @var{type})
* Determine if a type is a structure.
* @end deftypefun
@*/
int jit_type_is_struct(jit_type_t type)
{
if(type)
{
return (type->kind == JIT_TYPE_STRUCT);
}
else
{
return 0;
}
}
/*@
* @deftypefun int jit_type_is_union (jit_type_t @var{type})
* Determine if a type is a union.
* @end deftypefun
@*/
int jit_type_is_union(jit_type_t type)
{
if(type)
{
return (type->kind == JIT_TYPE_UNION);
}
else
{
return 0;
}
}
/*@
* @deftypefun int jit_type_is_signature (jit_type_t @var{type})
* Determine if a type is a function signature.
* @end deftypefun
@*/
int jit_type_is_signature(jit_type_t type)
{
if(type)
{
return (type->kind == JIT_TYPE_SIGNATURE);
}
else
{
return 0;
}
}
/*@
* @deftypefun int jit_type_is_pointer (jit_type_t @var{type})
* Determine if a type is a pointer.
* @end deftypefun
@*/
int jit_type_is_pointer(jit_type_t type)
{
if(type)
{
return (type->kind == JIT_TYPE_PTR);
}
else
{
return 0;
}
}
/*@
* @deftypefun int jit_type_is_tagged (jit_type_t @var{type})
* Determine if a type is a tagged type.
* @end deftypefun
@*/
int jit_type_is_tagged(jit_type_t type)
{
if(type)
{
return (type->kind >= JIT_TYPE_FIRST_TAGGED);
}
else
{
return 0;
}
}
/*@
* @deftypefun jit_nuint jit_type_best_alignment (void)
* Get the best alignment value for this platform.
* @end deftypefun
@*/
jit_nuint jit_type_best_alignment(void)
{
return JIT_BEST_ALIGNMENT;
}
/*@
* @deftypefun jit_type_t jit_type_normalize (jit_type_t @var{type})
* Normalize a type to its basic numeric form. e.g. "jit_type_nint" is
* turned into "jit_type_int" or "jit_type_long", depending upon
* the underlying platform. Pointers are normalized like "jit_type_nint".
* If the type does not have a normalized form, it is left unchanged.
*
* Normalization is typically used prior to applying a binary numeric
* instruction, to make it easier to determine the common type.
* It will also remove tags from the specified type.
* @end deftypefun
@*/
jit_type_t jit_type_normalize(jit_type_t type)
{
while(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
{
/* Remove any tags that are attached to the type */
type = type->sub_type;
}
if(!type)
{
return type;
}
if(type == jit_type_nint || type->kind == JIT_TYPE_PTR ||
type->kind == JIT_TYPE_SIGNATURE)
{
#ifdef JIT_NATIVE_INT32
return jit_type_int;
#else
return jit_type_long;
#endif
}
else if(type == jit_type_nuint)
{
#ifdef JIT_NATIVE_INT32
return jit_type_uint;
#else
return jit_type_ulong;
#endif
}
else if(type == jit_type_nfloat)
{
if(sizeof(jit_nfloat) == sizeof(jit_float64))
{
return jit_type_float64;
}
else if(sizeof(jit_nfloat) == sizeof(jit_float32))
{
return jit_type_float32;
}
}
return type;
}
/*@
* @deftypefun jit_type_t jit_type_remove_tags (jit_type_t @var{type})
* Remove tags from a type, and return the underlying type.
* This is different from normalization, which will also collapses
* native types to their basic numeric counterparts.
* @end deftypefun
@*/
jit_type_t jit_type_remove_tags(jit_type_t type)
{
while(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
{
type = type->sub_type;
}
return type;
}
/*@
* @deftypefun jit_type_t jit_type_promote_int (jit_type_t @var{type})
* If @var{type} is @code{jit_type_sbyte} or @code{jit_type_short},
* then return @code{jit_type_int}. If @var{type} is
* @code{jit_type_ubyte} or @code{jit_type_ushort}, then return
* @code{jit_type_uint}. Otherwise return @var{type} as-is.
* @end deftypefun
@*/
jit_type_t jit_type_promote_int(jit_type_t type)
{
if(type == jit_type_sbyte || type == jit_type_short)
{
return jit_type_int;
}
else if(type == jit_type_ubyte || type == jit_type_ushort)
{
return jit_type_uint;
}
else
{
return type;
}
}
/*@
* @deftypefun int jit_type_return_via_pointer (jit_type_t @var{type})
* Determine if a type should be returned via a pointer if it appears
* as the return type in a signature.
* @end deftypefun
@*/
int jit_type_return_via_pointer(jit_type_t type)
{
extern unsigned char const _jit_apply_return_in_reg[];
unsigned int size;
/* Normalize the type first, just in case the structure is tagged */
type = jit_type_normalize(type);
/* Only structure and union types require special handling */
if(!jit_type_is_struct(type) && !jit_type_is_union(type))
{
return 0;
}
/* Determine if the structure can be returned in a register */
size = jit_type_get_size(type);
if(size >= 1 && size <= 64)
{
if((_jit_apply_return_in_reg[(size - 1) / 8] &
(1 << ((size - 1) % 8))) != 0)
{
return 0;
}
}
return 1;
}
/*@
* @deftypefun int jit_type_has_tag (jit_type_t @var{type}, int @var{kind})
* Determine if @var{type} has a specific kind of tag. This will
* resolve multiple levels of tagging.
* @end deftypefun
@*/
int jit_type_has_tag(jit_type_t type, int kind)
{
while(type != 0 && type->kind >= JIT_TYPE_FIRST_TAGGED)
{
if(type->kind == (JIT_TYPE_FIRST_TAGGED + kind))
{
return 1;
}
type = type->sub_type;
}
return 0;
}