mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
1774 lines
43 KiB
C
1774 lines
43 KiB
C
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
|
// Use of this source code is governed by the GNU LGPLv3.0 license
|
|
// a copy of which can be found in the LICENSE file.
|
|
|
|
#include "compiler_internal.h"
|
|
|
|
static STable function_types;
|
|
static struct
|
|
{
|
|
Type u0, u1, i8, i16, i32, i64, i128, ixx;
|
|
Type u8, u16, u32, u64, u128;
|
|
Type f16, f32, f64, f128, fxx;
|
|
Type usz, isz, uptr, iptr, uptrdiff, iptrdiff;
|
|
Type voidstar, typeid, anyerr, typeinfo, ctlist;
|
|
Type str, virtual, virtual_generic, anyfail;
|
|
} t;
|
|
|
|
Type *type_bool = &t.u1;
|
|
Type *type_void = &t.u0;
|
|
Type *type_voidptr = &t.voidstar;
|
|
Type *type_virtual = &t.virtual;
|
|
Type *type_virtual_generic = &t.virtual_generic;
|
|
Type *type_half = &t.f16;
|
|
Type *type_float = &t.f32;
|
|
Type *type_double = &t.f64;
|
|
Type *type_quad = &t.f128;
|
|
Type *type_typeid = &t.typeid;
|
|
Type *type_typeinfo = &t.typeinfo;
|
|
Type *type_ichar = &t.i8;
|
|
Type *type_short = &t.i16;
|
|
Type *type_int = &t.i32;
|
|
Type *type_long = &t.i64;
|
|
Type *type_i128 = &t.i128;
|
|
Type *type_iptr = &t.iptr;
|
|
Type *type_iptrdiff = &t.iptrdiff;
|
|
Type *type_isize = &t.isz;
|
|
Type *type_char = &t.u8;
|
|
Type *type_ushort = &t.u16;
|
|
Type *type_uint = &t.u32;
|
|
Type *type_ulong = &t.u64;
|
|
Type *type_u128 = &t.u128;
|
|
Type *type_uptr = &t.uptr;
|
|
Type *type_uptrdiff = &t.uptrdiff;
|
|
Type *type_usize = &t.usz;
|
|
Type *type_compstr = &t.str;
|
|
Type *type_anyerr = &t.anyerr;
|
|
Type *type_complist = &t.ctlist;
|
|
Type *type_anyfail = &t.anyfail;
|
|
|
|
static unsigned size_subarray;
|
|
static AlignSize alignment_subarray;
|
|
static AlignSize max_alignment_vector;
|
|
|
|
#define PTR_OFFSET 0
|
|
#define INFERRED_ARRAY_OFFSET 1
|
|
#define SUB_ARRAY_OFFSET 2
|
|
#define FAILABLE_OFFSET 3
|
|
#define ARRAY_OFFSET 4
|
|
|
|
Type *type_cint(void)
|
|
{
|
|
return type_int_signed_by_bitsize(platform_target.width_c_int);
|
|
}
|
|
|
|
Type *type_cuint(void)
|
|
{
|
|
return type_int_unsigned_by_bitsize(platform_target.width_c_int);
|
|
}
|
|
|
|
Type *type_int_signed_by_bitsize(unsigned bitsize)
|
|
{
|
|
switch (bitsize)
|
|
{
|
|
case 8: return type_ichar;
|
|
case 16: return type_short;
|
|
case 32: return type_int;
|
|
case 64: return type_long;
|
|
case 128: return type_i128;
|
|
default: FATAL_ERROR("Illegal bitsize %d", bitsize);
|
|
}
|
|
}
|
|
Type *type_int_unsigned_by_bitsize(unsigned bytesize)
|
|
{
|
|
switch (bytesize)
|
|
{
|
|
case 8: return type_char;
|
|
case 16: return type_ushort;
|
|
case 32: return type_uint;
|
|
case 64: return type_ulong;
|
|
case 128: return type_u128;
|
|
default: FATAL_ERROR("Illegal bitsize %d", bytesize);
|
|
}
|
|
}
|
|
|
|
const char *type_quoted_error_string(Type *type)
|
|
{
|
|
char *buffer = NULL;
|
|
if (type->canonical != type)
|
|
{
|
|
asprintf(&buffer, "'%s' (%s)", type_to_error_string(type), type_to_error_string(type->canonical));
|
|
return buffer;
|
|
}
|
|
asprintf(&buffer, "'%s'", type_to_error_string(type));
|
|
return buffer;
|
|
}
|
|
const char *type_to_error_string(Type *type)
|
|
{
|
|
char *buffer = NULL;
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_POISONED:
|
|
return "poisoned";
|
|
case TYPE_ENUM:
|
|
case TYPE_ERRTYPE:
|
|
case TYPE_TYPEDEF:
|
|
case TYPE_STRUCT:
|
|
case TYPE_VOID:
|
|
case TYPE_BOOL:
|
|
case ALL_INTS:
|
|
case ALL_FLOATS:
|
|
case TYPE_UNION:
|
|
case TYPE_DISTINCT:
|
|
case TYPE_BITSTRUCT:
|
|
case TYPE_VIRTUAL_ANY:
|
|
case TYPE_VIRTUAL:
|
|
case TYPE_ANYERR:
|
|
case TYPE_UNTYPED_LIST:
|
|
return type->name;
|
|
case TYPE_FUNC:
|
|
return strcat_arena("func ", type->func.mangled_function_signature);
|
|
case TYPE_VECTOR:
|
|
asprintf(&buffer, "%s[<%llu>]", type_to_error_string(type->array.base), (unsigned long long)type->array.len);
|
|
return buffer;
|
|
case TYPE_TYPEINFO:
|
|
return "typeinfo";
|
|
case TYPE_TYPEID:
|
|
return "typeid";
|
|
case TYPE_FAILABLE_ANY:
|
|
return "void!";
|
|
case TYPE_POINTER:
|
|
if (type->pointer->type_kind == TYPE_FUNC)
|
|
{
|
|
return type_to_error_string(type->pointer);
|
|
}
|
|
asprintf(&buffer, "%s*", type_to_error_string(type->pointer));
|
|
return buffer;
|
|
case TYPE_FAILABLE:
|
|
if (!type->failable) return "void!";
|
|
asprintf(&buffer, "%s!", type_to_error_string(type->failable));
|
|
return buffer;
|
|
case TYPE_STRLIT:
|
|
return "string literal";
|
|
case TYPE_ARRAY:
|
|
asprintf(&buffer, "%s[%llu]", type_to_error_string(type->array.base), (unsigned long long)type->array.len);
|
|
return buffer;
|
|
case TYPE_INFERRED_ARRAY:
|
|
asprintf(&buffer, "%s[*]", type_to_error_string(type->array.base));
|
|
return buffer;
|
|
case TYPE_SUBARRAY:
|
|
asprintf(&buffer, "%s[]", type_to_error_string(type->array.base));
|
|
return buffer;
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
|
|
void type_append_signature_name(Type *type, char *dst, size_t *offset)
|
|
{
|
|
type = type->canonical;
|
|
assert(*offset < MAX_FUNCTION_SIGNATURE_SIZE);
|
|
const char *name;
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_POISONED:
|
|
case TYPE_TYPEDEF:
|
|
UNREACHABLE;
|
|
case TYPE_ERRTYPE:
|
|
case TYPE_ENUM:
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
name = type->decl->external_name;
|
|
break;
|
|
default:
|
|
name = type->name;
|
|
break;
|
|
}
|
|
memcpy(dst + *offset, name, strlen(name));
|
|
*offset += strlen(name);
|
|
}
|
|
|
|
|
|
|
|
ByteSize type_size(Type *type)
|
|
{
|
|
RETRY:
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_BITSTRUCT:
|
|
type = type->decl->bitstruct.base_type->type;
|
|
goto RETRY;
|
|
case TYPE_DISTINCT:
|
|
type = type->decl->distinct_decl.base_type;
|
|
goto RETRY;
|
|
case TYPE_VECTOR:
|
|
{
|
|
ByteSize width = type_size(type->vector.base) * type->vector.len;
|
|
if (width & (width - 1))
|
|
{
|
|
ByteSize alignment = next_highest_power_of_2(width);
|
|
width = aligned_offset(width, alignment);
|
|
}
|
|
return width;
|
|
}
|
|
case CT_TYPES:
|
|
UNREACHABLE;
|
|
case TYPE_FAILABLE:
|
|
type = type->failable;
|
|
goto RETRY;
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
goto RETRY;
|
|
case TYPE_ERRTYPE:
|
|
type = type_iptr->canonical;
|
|
goto RETRY;
|
|
case TYPE_ENUM:
|
|
return type->decl->enums.type_info->type->canonical->builtin.bytesize;
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
assert(type->decl->resolve_status == RESOLVE_DONE);
|
|
return type->decl->strukt.size;
|
|
case TYPE_VOID:
|
|
case TYPE_FAILABLE_ANY:
|
|
return 1;
|
|
case TYPE_BOOL:
|
|
case TYPE_TYPEID:
|
|
case ALL_INTS:
|
|
case ALL_FLOATS:
|
|
case TYPE_ANYERR:
|
|
case TYPE_VIRTUAL_ANY:
|
|
return type->builtin.bytesize;
|
|
case TYPE_VIRTUAL:
|
|
return type_virtual_generic->builtin.bytesize;
|
|
case TYPE_STRLIT:
|
|
case TYPE_FUNC:
|
|
case TYPE_POINTER:
|
|
return t.iptr.canonical->builtin.bytesize;
|
|
case TYPE_ARRAY:
|
|
return type_size(type->array.base) * type->array.len;
|
|
case TYPE_SUBARRAY:
|
|
return size_subarray;
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
|
|
const char *type_generate_qname(Type *type)
|
|
{
|
|
if (type_is_builtin(type->type_kind)) return type->name;
|
|
return strformat("%s::%s", type->decl->module->name->module, type->name);
|
|
}
|
|
|
|
|
|
|
|
bool type_is_union_struct(Type *type)
|
|
{
|
|
TypeKind kind = type->canonical->type_kind;
|
|
return kind == TYPE_STRUCT || kind == TYPE_UNION;
|
|
}
|
|
|
|
bool type_is_empty_field(Type *type, bool allow_array)
|
|
{
|
|
type = type_lowering(type);
|
|
if (allow_array)
|
|
{
|
|
while (type->type_kind == TYPE_ARRAY)
|
|
{
|
|
if (type->array.len == 0) return true;
|
|
type = type_lowering(type->array.base);
|
|
}
|
|
}
|
|
return type_is_empty_record(type, allow_array);
|
|
}
|
|
|
|
bool type_is_empty_record(Type *type, bool allow_array)
|
|
{
|
|
if (!type_is_union_struct(type)) return false;
|
|
|
|
Decl *decl = type->decl;
|
|
if (decl->has_variable_array) return false;
|
|
|
|
Decl **members = decl->strukt.members;
|
|
VECEACH(members, i)
|
|
{
|
|
if (!type_is_empty_field(members[i]->type, allow_array)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool type_is_int128(Type *type)
|
|
{
|
|
TypeKind kind = type->canonical->type_kind;
|
|
return kind == TYPE_U128 || kind == TYPE_I128;
|
|
}
|
|
|
|
/**
|
|
* Based on isSingleElementStruct in Clang
|
|
*/
|
|
Type *type_abi_find_single_struct_element(Type *type)
|
|
{
|
|
if (!type_is_structlike(type)) return NULL;
|
|
|
|
// Elements with a variable array? If so no.
|
|
if (type->decl->has_variable_array) return NULL;
|
|
|
|
Type *found = NULL;
|
|
Decl **members = type->decl->strukt.members;
|
|
VECEACH(members, i)
|
|
{
|
|
Type *field_type = type_lowering(members[i]->type);
|
|
|
|
// Ignore empty arrays
|
|
if (type_is_empty_field(field_type, true)) continue;
|
|
|
|
// Already one field found, not single field.
|
|
if (found) return NULL;
|
|
|
|
// Flatten single element arrays.
|
|
while (field_type->type_kind == TYPE_ARRAY)
|
|
{
|
|
if (field_type->array.len != 1) break;
|
|
field_type = field_type->array.base;
|
|
}
|
|
|
|
if (type_is_structlike(field_type))
|
|
{
|
|
field_type = type_abi_find_single_struct_element(field_type);
|
|
if (!field_type) return NULL;
|
|
}
|
|
found = field_type;
|
|
}
|
|
// If there is some padding? Then ignore.
|
|
if (found && type_size(type) != type_size(found)) found = NULL;
|
|
return found;
|
|
}
|
|
|
|
|
|
|
|
bool type_is_abi_aggregate(Type *type)
|
|
{
|
|
RETRY:
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_POISONED:
|
|
return false;
|
|
case TYPE_FAILABLE:
|
|
type = type->failable;
|
|
goto RETRY;
|
|
case TYPE_DISTINCT:
|
|
type = type->decl->distinct_decl.base_type;
|
|
goto RETRY;
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
goto RETRY;
|
|
case TYPE_BITSTRUCT:
|
|
case ALL_FLOATS:
|
|
case TYPE_VOID:
|
|
case TYPE_FAILABLE_ANY:
|
|
case ALL_INTS:
|
|
case TYPE_BOOL:
|
|
case TYPE_TYPEID:
|
|
case TYPE_POINTER:
|
|
case TYPE_ENUM:
|
|
case TYPE_FUNC:
|
|
case TYPE_STRLIT:
|
|
case TYPE_VECTOR:
|
|
case TYPE_ANYERR:
|
|
case TYPE_ERRTYPE:
|
|
return false;
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
case TYPE_SUBARRAY:
|
|
case TYPE_ARRAY:
|
|
case TYPE_VIRTUAL:
|
|
case TYPE_VIRTUAL_ANY:
|
|
return true;
|
|
case TYPE_TYPEINFO:
|
|
case TYPE_INFERRED_ARRAY:
|
|
case TYPE_UNTYPED_LIST:
|
|
UNREACHABLE
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
bool type_is_homogenous_base_type(Type *type)
|
|
{
|
|
type = type->canonical;
|
|
switch (platform_target.abi)
|
|
{
|
|
case ABI_PPC64_SVR4:
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_F128:
|
|
if (!platform_target.float128) return false;
|
|
FALLTHROUGH;
|
|
case TYPE_F32:
|
|
case TYPE_F64:
|
|
return !platform_target.ppc64.is_softfp;
|
|
case TYPE_VECTOR:
|
|
return type_size(type) == 128 / 8;
|
|
default:
|
|
return false;
|
|
}
|
|
case ABI_X64:
|
|
case ABI_WIN64:
|
|
case ABI_X86:
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_F64:
|
|
case TYPE_F32:
|
|
return true;
|
|
case TYPE_VECTOR:
|
|
switch (type_size(type))
|
|
{
|
|
case 16:
|
|
case 32:
|
|
case 64:
|
|
// vec128 256 512 ok
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
case ABI_AARCH64:
|
|
switch (type->type_kind)
|
|
{
|
|
case ALL_FLOATS:
|
|
return true;
|
|
case TYPE_VECTOR:
|
|
switch (type_size(type))
|
|
{
|
|
case 8:
|
|
case 16:
|
|
// vector 64, 128 => true
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
case ABI_ARM:
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_F32:
|
|
case TYPE_F64:
|
|
case TYPE_F128:
|
|
return true;
|
|
case TYPE_VECTOR:
|
|
switch (type_size(type))
|
|
{
|
|
case 8:
|
|
case 16:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
FALLTHROUGH;
|
|
default:
|
|
return false;
|
|
}
|
|
case ABI_UNKNOWN:
|
|
case ABI_WASM:
|
|
case ABI_PPC32:
|
|
case ABI_RISCV:
|
|
return false;
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
|
|
bool type_homogenous_aggregate_small_enough(Type *type, unsigned members)
|
|
{
|
|
switch (platform_target.abi)
|
|
{
|
|
case ABI_PPC64_SVR4:
|
|
if (type->type_kind == TYPE_F128 && platform_target.float128) return members <= 8;
|
|
if (type->type_kind == TYPE_VECTOR) return members <= 8;
|
|
// Use max 8 registers.
|
|
return ((type_size(type) + 7) / 8) * members <= 8;
|
|
case ABI_X64:
|
|
case ABI_WIN64:
|
|
case ABI_X86:
|
|
case ABI_AARCH64:
|
|
case ABI_ARM:
|
|
return members <= 4;
|
|
case ABI_UNKNOWN:
|
|
case ABI_WASM:
|
|
case ABI_PPC32:
|
|
case ABI_RISCV:
|
|
return false;
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
|
|
/**
|
|
* Calculate whether this is a homogenous aggregate for the ABI.
|
|
* // Based on bool ABIInfo::isHomogeneousAggregate in Clang
|
|
* @param type the (flattened) type to check.
|
|
* @param base the base type of the aggregate
|
|
* @param elements the elements found
|
|
* @return true if it is an aggregate, false otherwise.
|
|
*/
|
|
bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
|
|
{
|
|
*elements = 0;
|
|
RETRY:
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_FAILABLE:
|
|
type = type->failable;
|
|
goto RETRY;
|
|
case TYPE_DISTINCT:
|
|
type = type->decl->distinct_decl.base_type;
|
|
goto RETRY;
|
|
case TYPE_BITSTRUCT:
|
|
type = type->decl->bitstruct.base_type->type;
|
|
goto RETRY;
|
|
case TYPE_VOID:
|
|
case TYPE_TYPEID:
|
|
case TYPE_FUNC:
|
|
case TYPE_STRLIT:
|
|
case TYPE_SUBARRAY:
|
|
case CT_TYPES:
|
|
case TYPE_FAILABLE_ANY:
|
|
return false;
|
|
case TYPE_VIRTUAL:
|
|
case TYPE_VIRTUAL_ANY:
|
|
*base = type_iptr->canonical;
|
|
*elements = 2;
|
|
return true;
|
|
case TYPE_ANYERR:
|
|
case TYPE_ERRTYPE:
|
|
type = type_iptr;
|
|
goto RETRY;
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
goto RETRY;
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
if (type->decl->has_variable_array) return false;
|
|
*elements = 0;
|
|
{
|
|
Decl **members = type->decl->strukt.members;
|
|
VECEACH(members, i)
|
|
{
|
|
unsigned member_mult = 1;
|
|
// Flatten the type.
|
|
Type *member_type = type_lowering(members[i]->type);
|
|
// Go down deep into a nester array.
|
|
while (member_type->type_kind == TYPE_ARRAY)
|
|
{
|
|
// If we find a zero length array, this is not allowed.
|
|
if (member_type->array.len == 0) return false;
|
|
member_mult *= member_type->array.len;
|
|
member_type = member_type->array.base;
|
|
}
|
|
unsigned member_members = 0;
|
|
// Skip any empty record.
|
|
if (type_is_empty_record(member_type, true)) continue;
|
|
|
|
// Check recursively if the field member is homogenous
|
|
if (!type_is_homogenous_aggregate(member_type, base, &member_members)) return false;
|
|
member_members *= member_mult;
|
|
// In the case of a union, grab the bigger set of elements.
|
|
if (type->type_kind == TYPE_UNION)
|
|
{
|
|
*elements = MAX(*elements, member_members);
|
|
}
|
|
else
|
|
{
|
|
*elements += member_members;
|
|
}
|
|
}
|
|
assert(base);
|
|
if (!*base) return false;
|
|
|
|
// Ensure no padding
|
|
if (type_size(*base) * *elements != type_size(type)) return false;
|
|
}
|
|
goto TYPECHECK;
|
|
case TYPE_ARRAY:
|
|
// Empty arrays? Not homogenous.
|
|
if (type->array.len == 0) return false;
|
|
// Check the underlying type and multiply by length.
|
|
if (!type_is_homogenous_aggregate(type->array.base, base, elements)) return false;
|
|
*elements *= type->array.len;
|
|
goto TYPECHECK;
|
|
case TYPE_ENUM:
|
|
type = type->decl->enums.type_info->type;
|
|
goto RETRY;
|
|
case TYPE_BOOL:
|
|
// Lower bool to unsigned char
|
|
type = type_char;
|
|
break;
|
|
case ALL_SIGNED_INTS:
|
|
// Lower signed to unsigned
|
|
type = type_int_unsigned_by_bitsize(type->builtin.bitsize);
|
|
break;
|
|
case ALL_UNSIGNED_INTS:
|
|
case ALL_FLOATS:
|
|
case TYPE_VECTOR:
|
|
break;
|
|
case TYPE_POINTER:
|
|
// All pointers are the same.
|
|
type = type_voidptr;
|
|
break;
|
|
}
|
|
// The common case:
|
|
*elements = 1;
|
|
// Is it a valid base type?
|
|
if (!type_is_homogenous_base_type(type)) return false;
|
|
// If we don't have a base type yet, set it.
|
|
if (!*base)
|
|
{
|
|
*base = type;
|
|
// Special handling of non-power-of-2 vectors
|
|
if (type->type_kind == TYPE_VECTOR)
|
|
{
|
|
// Widen the type with elements.
|
|
unsigned vec_elements = type_size(type) / type_size(type->vector.base);
|
|
*base = type_get_vector(type->vector.base, vec_elements);
|
|
}
|
|
}
|
|
// One is vector - other isn't => failure
|
|
if (((*base)->type_kind == TYPE_VECTOR) != (type->type_kind == TYPE_VECTOR)) return false;
|
|
|
|
// Size does not match => failure
|
|
if (type_size(*base) != type_size(type)) return false;
|
|
|
|
TYPECHECK:
|
|
if (*elements == 0) return false;
|
|
return type_homogenous_aggregate_small_enough(type, *elements);
|
|
}
|
|
|
|
AlignSize type_alloca_alignment(Type *type)
|
|
{
|
|
if (platform_target.abi == ABI_X64)
|
|
{
|
|
type = type_lowering(type);
|
|
if (type->type_kind == TYPE_ARRAY && type_size(type) >= 16) return 16;
|
|
}
|
|
return type_abi_alignment(type);
|
|
}
|
|
|
|
Type *type_find_largest_union_element(Type *type)
|
|
{
|
|
assert(type->type_kind == TYPE_UNION);
|
|
ByteSize largest = 0;
|
|
Type *largest_type = NULL;
|
|
Decl **members = type->decl->strukt.members;
|
|
VECEACH(members, i)
|
|
{
|
|
if (type_size(type) > largest)
|
|
{
|
|
largest = type_size(type);
|
|
largest_type = type->canonical;
|
|
}
|
|
}
|
|
return largest_type;
|
|
}
|
|
|
|
bool type_is_ordered(Type *type)
|
|
{
|
|
RETRY:
|
|
switch (type->type_kind)
|
|
{
|
|
case ALL_FLOATS:
|
|
case ALL_INTS:
|
|
case TYPE_POINTER:
|
|
case TYPE_BOOL:
|
|
case TYPE_ENUM:
|
|
case TYPE_VECTOR:
|
|
return true;
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
goto RETRY;
|
|
case TYPE_DISTINCT:
|
|
type = type->decl->distinct_decl.base_type;
|
|
goto RETRY;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool type_is_comparable(Type *type)
|
|
{
|
|
RETRY:
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_INFERRED_ARRAY:
|
|
case TYPE_POISONED:
|
|
UNREACHABLE
|
|
case TYPE_VOID:
|
|
case TYPE_UNION:
|
|
case TYPE_STRUCT:
|
|
case TYPE_BITSTRUCT:
|
|
return false;
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
goto RETRY;
|
|
case TYPE_SUBARRAY:
|
|
case TYPE_ARRAY:
|
|
// Arrays are comparable if elements are
|
|
type = type->array.base;
|
|
goto RETRY;
|
|
case TYPE_DISTINCT:
|
|
type = type->decl->distinct_decl.base_type;
|
|
goto RETRY;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
AlignSize type_abi_alignment(Type *type)
|
|
{
|
|
RETRY:
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_POISONED:
|
|
case TYPE_TYPEINFO:
|
|
case TYPE_UNTYPED_LIST:
|
|
UNREACHABLE;
|
|
case TYPE_BITSTRUCT:
|
|
type = type->decl->bitstruct.base_type->type;
|
|
goto RETRY;
|
|
case TYPE_VECTOR:
|
|
{
|
|
ByteSize width = type_size(type->vector.base) * type->vector.len;
|
|
ByteSize alignment = width;
|
|
if (alignment & (alignment - 1))
|
|
{
|
|
alignment = next_highest_power_of_2(alignment);
|
|
}
|
|
if (max_alignment_vector && alignment > max_alignment_vector) alignment = max_alignment_vector;
|
|
return alignment;
|
|
}
|
|
case TYPE_VOID:
|
|
case TYPE_FAILABLE_ANY:
|
|
return 1;
|
|
case TYPE_FAILABLE:
|
|
type = type->failable;
|
|
goto RETRY;
|
|
case TYPE_DISTINCT:
|
|
type = type->decl->distinct_decl.base_type;
|
|
goto RETRY;
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
goto RETRY;
|
|
case TYPE_ENUM:
|
|
return type->decl->enums.type_info->type->canonical->builtin.abi_alignment;
|
|
case TYPE_ERRTYPE:
|
|
return t.iptr.canonical->builtin.abi_alignment;
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
return type->decl->alignment;
|
|
case TYPE_BOOL:
|
|
case ALL_INTS:
|
|
case ALL_FLOATS:
|
|
case TYPE_VIRTUAL_ANY:
|
|
case TYPE_ANYERR:
|
|
return type->builtin.abi_alignment;
|
|
case TYPE_VIRTUAL:
|
|
return type_virtual_generic->builtin.abi_alignment;
|
|
case TYPE_FUNC:
|
|
case TYPE_POINTER:
|
|
case TYPE_STRLIT:
|
|
case TYPE_TYPEID:
|
|
return t.iptr.canonical->builtin.abi_alignment;
|
|
case TYPE_ARRAY:
|
|
case TYPE_INFERRED_ARRAY:
|
|
type = type->array.base;
|
|
goto RETRY;
|
|
case TYPE_SUBARRAY:
|
|
return alignment_subarray;
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
|
|
static inline void create_type_cache(Type *type)
|
|
{
|
|
for (int i = 0; i < ARRAY_OFFSET; i++)
|
|
{
|
|
vec_add(type->type_cache, NULL);
|
|
}
|
|
}
|
|
|
|
static Type *type_generate_ptr(Type *ptr_type, bool canonical)
|
|
{
|
|
if (canonical) ptr_type = ptr_type->canonical;
|
|
if (!ptr_type->type_cache)
|
|
{
|
|
create_type_cache(ptr_type);
|
|
}
|
|
|
|
Type *ptr = ptr_type->type_cache[PTR_OFFSET];
|
|
if (ptr == NULL)
|
|
{
|
|
ptr = type_new(TYPE_POINTER, strformat("%s*", ptr_type->name));
|
|
ptr->pointer = ptr_type;
|
|
ptr_type->type_cache[PTR_OFFSET] = ptr;
|
|
if (ptr_type == ptr_type->canonical)
|
|
{
|
|
ptr->canonical = ptr;
|
|
}
|
|
else
|
|
{
|
|
ptr->canonical = type_generate_ptr(ptr_type->canonical, true);
|
|
}
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
static Type *type_generate_failable(Type *failable_type, bool canonical)
|
|
{
|
|
if (canonical) failable_type = failable_type->canonical;
|
|
if (!failable_type->type_cache)
|
|
{
|
|
create_type_cache(failable_type);
|
|
}
|
|
Type *failable = failable_type->type_cache[FAILABLE_OFFSET];
|
|
if (failable == NULL)
|
|
{
|
|
failable = type_new(TYPE_FAILABLE, strformat("%s!", failable_type->name));
|
|
failable->pointer = failable_type;
|
|
failable_type->type_cache[FAILABLE_OFFSET] = failable;
|
|
if (failable_type == failable_type->canonical)
|
|
{
|
|
failable->canonical = failable;
|
|
}
|
|
else
|
|
{
|
|
failable->canonical = type_generate_failable(failable_type->canonical, true);
|
|
}
|
|
}
|
|
return failable;
|
|
}
|
|
|
|
static Type *type_generate_subarray(Type *arr_type, bool canonical)
|
|
{
|
|
if (canonical) arr_type = arr_type->canonical;
|
|
if (!arr_type->type_cache)
|
|
{
|
|
create_type_cache(arr_type);
|
|
}
|
|
|
|
Type *arr = arr_type->type_cache[SUB_ARRAY_OFFSET];
|
|
if (arr == NULL)
|
|
{
|
|
arr = type_new(TYPE_SUBARRAY, strformat("%s[]", arr_type->name));
|
|
arr->array.base = arr_type;
|
|
arr_type->type_cache[SUB_ARRAY_OFFSET] = arr;
|
|
if (arr_type == arr_type->canonical)
|
|
{
|
|
arr->canonical = arr;
|
|
}
|
|
else
|
|
{
|
|
arr->canonical = type_generate_subarray(arr_type->canonical, true);
|
|
}
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
static Type *type_generate_inferred_array(Type *arr_type, bool canonical)
|
|
{
|
|
if (canonical) arr_type = arr_type->canonical;
|
|
if (!arr_type->type_cache)
|
|
{
|
|
create_type_cache(arr_type);
|
|
}
|
|
|
|
Type *arr = arr_type->type_cache[INFERRED_ARRAY_OFFSET];
|
|
if (arr == NULL)
|
|
{
|
|
arr = type_new(TYPE_INFERRED_ARRAY, strformat("%s[*]", arr_type->name));
|
|
arr->array.base = arr_type;
|
|
arr_type->type_cache[INFERRED_ARRAY_OFFSET] = arr;
|
|
if (arr_type == arr_type->canonical)
|
|
{
|
|
arr->canonical = arr;
|
|
}
|
|
else
|
|
{
|
|
arr->canonical = type_generate_inferred_array(arr_type->canonical, true);
|
|
}
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
|
|
Type *type_get_ptr_recurse(Type *ptr_type)
|
|
{
|
|
assert(ptr_type->type_kind != TYPE_FAILABLE_ANY);
|
|
if (ptr_type->type_kind == TYPE_FAILABLE)
|
|
{
|
|
ptr_type = ptr_type->failable;
|
|
return type_get_failable(type_get_ptr(ptr_type));
|
|
}
|
|
return type_get_ptr(ptr_type);
|
|
|
|
}
|
|
Type *type_get_ptr(Type *ptr_type)
|
|
{
|
|
assert(!type_is_failable(ptr_type));
|
|
return type_generate_ptr(ptr_type, false);
|
|
}
|
|
|
|
Type *type_get_failable(Type *failable_type)
|
|
{
|
|
assert(!type_is_failable(failable_type));
|
|
return type_generate_failable(failable_type, false);
|
|
}
|
|
|
|
Type *type_get_subarray(Type *arr_type)
|
|
{
|
|
return type_generate_subarray(arr_type, false);
|
|
}
|
|
|
|
Type *type_get_inferred_array(Type *arr_type)
|
|
{
|
|
return type_generate_inferred_array(arr_type, false);
|
|
}
|
|
|
|
static inline bool array_structurally_equivalent_to_struct(Type *array, Type *type)
|
|
{
|
|
assert(array->type_kind == TYPE_ARRAY);
|
|
|
|
ByteSize len = array->array.len;
|
|
if (!len) return type_size(type) == 0;
|
|
|
|
Type *base = array->array.base;
|
|
|
|
if (len == 1 && type_is_structurally_equivalent(base, type)) return true;
|
|
|
|
assert(type->type_kind != TYPE_UNION && "Does not work on unions");
|
|
|
|
if (!type_is_structlike(type)) return false;
|
|
|
|
Decl **members = type->decl->strukt.members;
|
|
|
|
// For structs / errors, all members must match.
|
|
ArrayIndex offset = 0;
|
|
AlignSize align_size = type_abi_alignment(array);
|
|
Type *array_base = array->array.base;
|
|
VECEACH(members, i)
|
|
{
|
|
if (!type_is_structurally_equivalent(array_base, members[i]->type)) return false;
|
|
if (members[i]->offset != offset) return false;
|
|
offset += align_size;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool type_is_structurally_equivalent(Type *type1, Type *type2)
|
|
{
|
|
type1 = type_flatten(type1);
|
|
type2 = type_flatten(type2);
|
|
|
|
if (type1 == type2) return true;
|
|
|
|
// If the other type is a union, we check against every member
|
|
// noting that there is only structural equivalence if it fills out the
|
|
if (type2->type_kind == TYPE_UNION)
|
|
{
|
|
Decl **members = type2->decl->strukt.members;
|
|
// If any member is structurally equivalent, then
|
|
// the cast is valid.
|
|
VECEACH(members, i)
|
|
{
|
|
if (type_is_structurally_equivalent(type1, members[i]->type)) return true;
|
|
}
|
|
// In this case we can't get a match.
|
|
return false;
|
|
}
|
|
|
|
if (type1->type_kind == TYPE_ARRAY)
|
|
{
|
|
return array_structurally_equivalent_to_struct(type1, type2);
|
|
}
|
|
|
|
if (type2->type_kind == TYPE_ARRAY)
|
|
{
|
|
return array_structurally_equivalent_to_struct(type2, type1);
|
|
}
|
|
|
|
if (!type_is_structlike(type1)) return false;
|
|
|
|
Decl **members = type1->decl->strukt.members;
|
|
if (type1->type_kind == TYPE_UNION)
|
|
{
|
|
// If any member is structurally equivalent, then
|
|
// the cast is valid.
|
|
VECEACH(members, i)
|
|
{
|
|
if (type_is_structurally_equivalent(members[i]->type, type2)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// The only thing we have left is to check against another structlike.
|
|
if (!type_is_structlike(type2)) return false;
|
|
|
|
Decl **other_members = type2->decl->strukt.members;
|
|
|
|
// For structs / errors, all members must match.
|
|
VECEACH(members, i)
|
|
{
|
|
if (!type_is_structurally_equivalent(members[i]->type, other_members[i]->type)) return false;
|
|
if (members[i]->offset != other_members[i]->offset) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool type_is_user_defined(Type *type)
|
|
{
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_ENUM:
|
|
case TYPE_FUNC:
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
case TYPE_ERRTYPE:
|
|
case TYPE_TYPEDEF:
|
|
case TYPE_DISTINCT:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Type *type_get_indexed_type(Type *type)
|
|
{
|
|
RETRY:
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_POINTER:
|
|
return type->pointer;
|
|
case TYPE_ARRAY:
|
|
case TYPE_SUBARRAY:
|
|
case TYPE_INFERRED_ARRAY:
|
|
case TYPE_VECTOR:
|
|
return type->array.base;
|
|
case TYPE_STRLIT:
|
|
return type_char;
|
|
case TYPE_DISTINCT:
|
|
type = type->decl->distinct_decl.base_type;
|
|
goto RETRY;
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
goto RETRY;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static Type *type_create_array(Type *element_type, uint64_t len, bool vector, bool canonical)
|
|
{
|
|
if (canonical) element_type = element_type->canonical;
|
|
if (!element_type->type_cache)
|
|
{
|
|
create_type_cache(element_type);
|
|
}
|
|
int entries = (int)vec_size(element_type->type_cache);
|
|
for (int i = ARRAY_OFFSET; i < entries; i++)
|
|
{
|
|
Type *ptr_vec = element_type->type_cache[i];
|
|
if (vector)
|
|
{
|
|
if (ptr_vec->type_kind != TYPE_VECTOR) continue;
|
|
if (ptr_vec->vector.len == len) return ptr_vec;
|
|
}
|
|
else
|
|
{
|
|
if (ptr_vec->type_kind == TYPE_VECTOR) continue;
|
|
if (ptr_vec->array.len == len) return ptr_vec;
|
|
}
|
|
}
|
|
Type *vec_arr;
|
|
if (vector)
|
|
{
|
|
vec_arr = type_new(TYPE_VECTOR, strformat("%s[<%llu>]", element_type->name, len));
|
|
vec_arr->vector.base = element_type;
|
|
vec_arr->vector.len = len;
|
|
}
|
|
else
|
|
{
|
|
vec_arr = type_new(TYPE_ARRAY, strformat("%s[%llu]", element_type->name, len));
|
|
vec_arr->array.base = element_type;
|
|
vec_arr->array.len = len;
|
|
}
|
|
if (element_type->canonical == element_type)
|
|
{
|
|
vec_arr->canonical = vec_arr;
|
|
}
|
|
else
|
|
{
|
|
vec_arr->canonical = type_create_array(element_type, len, vector, true);
|
|
}
|
|
vec_add(element_type->type_cache, vec_arr);
|
|
return vec_arr;
|
|
}
|
|
|
|
Type *type_get_array(Type *arr_type, ByteSize len)
|
|
{
|
|
return type_create_array(arr_type, len, false, false);
|
|
}
|
|
|
|
bool type_is_valid_for_vector(Type *type)
|
|
{
|
|
RETRY:
|
|
switch (type->type_kind)
|
|
{
|
|
case ALL_INTS:
|
|
case ALL_FLOATS:
|
|
case TYPE_BOOL:
|
|
return true;
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
goto RETRY;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Type *type_get_vector_bool(Type *original_type)
|
|
{
|
|
Type *type = type_flatten(original_type);
|
|
ByteSize size = type_size(type->vector.base);
|
|
return type_get_vector(type_int_signed_by_bitsize(size * 8), original_type->vector.len);
|
|
}
|
|
|
|
Type *type_get_vector(Type *vector_type, unsigned len)
|
|
{
|
|
return type_create_array(vector_type, len, true, false);
|
|
}
|
|
|
|
static void type_create(const char *name, Type *location, TypeKind kind, unsigned bitsize,
|
|
unsigned align, unsigned pref_align)
|
|
{
|
|
assert(align);
|
|
unsigned byte_size = (bitsize + 7) / 8;
|
|
*location = (Type) {
|
|
.type_kind = kind,
|
|
.builtin.bytesize = byte_size,
|
|
.builtin.bitsize = bitsize,
|
|
.builtin.abi_alignment = align,
|
|
.builtin.pref_alignment = pref_align ? pref_align : align,
|
|
.name = name,
|
|
.canonical = location,
|
|
};
|
|
location->name = name;
|
|
location->canonical = location;
|
|
global_context_add_type(location);
|
|
}
|
|
|
|
static void type_init(const char *name, Type *location, TypeKind kind, unsigned bitsize, AlignData align)
|
|
{
|
|
assert(align.align);
|
|
unsigned byte_size = (bitsize + 7) / 8;
|
|
*location = (Type) {
|
|
.type_kind = kind,
|
|
.builtin.bytesize = byte_size,
|
|
.builtin.bitsize = bitsize,
|
|
.builtin.abi_alignment = align.align / 8,
|
|
.builtin.pref_alignment = (align.pref_align ? align.pref_align : align.align) / 8,
|
|
.name = name,
|
|
.canonical = location,
|
|
};
|
|
location->name = name;
|
|
location->canonical = location;
|
|
global_context_add_type(location);
|
|
}
|
|
|
|
static void type_create_alias(const char *name, Type *location, Type *canonical)
|
|
{
|
|
*location = (Type) {
|
|
.type_kind = TYPE_TYPEDEF,
|
|
.name = name,
|
|
.canonical = canonical
|
|
};
|
|
global_context_add_type(location);
|
|
}
|
|
|
|
|
|
static void type_append_name_to_scratch(Type *type)
|
|
{
|
|
type = type->canonical;
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_POISONED:
|
|
case TYPE_TYPEDEF:
|
|
UNREACHABLE;
|
|
case TYPE_ERRTYPE:
|
|
case TYPE_ENUM:
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
case TYPE_DISTINCT:
|
|
case TYPE_BITSTRUCT:
|
|
scratch_buffer_append(type->decl->external_name);
|
|
break;
|
|
case TYPE_POINTER:
|
|
type_append_name_to_scratch(type->pointer);
|
|
scratch_buffer_append_char('*');
|
|
break;
|
|
case TYPE_FAILABLE_ANY:
|
|
scratch_buffer_append("void!");
|
|
break;
|
|
case TYPE_FAILABLE:
|
|
if (type->failable)
|
|
{
|
|
type_append_name_to_scratch(type->failable);
|
|
}
|
|
else
|
|
{
|
|
scratch_buffer_append("void");
|
|
}
|
|
scratch_buffer_append_char('!');
|
|
break;
|
|
case TYPE_SUBARRAY:
|
|
type_append_name_to_scratch(type->pointer);
|
|
scratch_buffer_append("[]");
|
|
case TYPE_VOID:
|
|
case TYPE_BOOL:
|
|
case TYPE_I8:
|
|
case TYPE_I16:
|
|
case TYPE_I32:
|
|
case TYPE_I64:
|
|
case TYPE_I128:
|
|
case TYPE_U8:
|
|
case TYPE_U16:
|
|
case TYPE_U32:
|
|
case TYPE_U64:
|
|
case TYPE_U128:
|
|
case TYPE_F16:
|
|
case TYPE_F32:
|
|
case TYPE_F64:
|
|
case TYPE_F128:
|
|
case TYPE_TYPEID:
|
|
case TYPE_ANYERR:
|
|
case TYPE_VIRTUAL_ANY:
|
|
case TYPE_VECTOR:
|
|
scratch_buffer_append(type->name);
|
|
break;
|
|
case TYPE_STRLIT:
|
|
case TYPE_UNTYPED_LIST:
|
|
case TYPE_INFERRED_ARRAY:
|
|
case TYPE_TYPEINFO:
|
|
UNREACHABLE
|
|
break;
|
|
case TYPE_FUNC:
|
|
scratch_buffer_append(type->func.mangled_function_signature);
|
|
break;
|
|
case TYPE_ARRAY:
|
|
type_append_name_to_scratch(type->array.base);
|
|
scratch_buffer_append_char('[');
|
|
scratch_buffer_append_signed_int(type->array.len);
|
|
scratch_buffer_append_char(']');
|
|
break;
|
|
case TYPE_VIRTUAL:
|
|
scratch_buffer_append("virtual ");
|
|
scratch_buffer_append(type->decl->name);
|
|
}
|
|
}
|
|
|
|
Type *type_find_function_type(FunctionSignature *signature)
|
|
{
|
|
scratch_buffer_clear();
|
|
type_append_name_to_scratch(signature->rtype->type);
|
|
scratch_buffer_append_char('(');
|
|
unsigned elements = vec_size(signature->params);
|
|
for (unsigned i = 0; i < elements; i++)
|
|
{
|
|
if (i > 0)
|
|
{
|
|
scratch_buffer_append_char(',');
|
|
}
|
|
type_append_name_to_scratch(signature->params[i]->var.type_info->type);
|
|
}
|
|
if (signature->variadic == VARIADIC_RAW && elements > 0)
|
|
{
|
|
scratch_buffer_append_char(',');
|
|
}
|
|
if (signature->variadic != VARIADIC_NONE)
|
|
{
|
|
scratch_buffer_append("...");
|
|
}
|
|
scratch_buffer_append_char(')');
|
|
const char *mangled_signature = scratch_buffer_interned();
|
|
Type *func_type = stable_get(&function_types, mangled_signature);
|
|
if (!func_type)
|
|
{
|
|
func_type = type_new(TYPE_FUNC, mangled_signature);
|
|
func_type->canonical = func_type;
|
|
func_type->func.signature = signature;
|
|
func_type->func.mangled_function_signature = mangled_signature;
|
|
stable_set(&function_types, mangled_signature, func_type);
|
|
}
|
|
return func_type;
|
|
}
|
|
|
|
static inline void type_init_int(const char *name, Type *type, TypeKind kind, BitSizes bits)
|
|
{
|
|
int actual_bits = bits ? 8 << (bits - 1) : 1;
|
|
type_init(name, type, kind, actual_bits, platform_target.integers[bits]);
|
|
}
|
|
|
|
static inline void type_create_float(const char *name, Type *type, TypeKind kind, BitSizes bits)
|
|
{
|
|
int actual_bits = bits ? 8 << (bits - 1) : 1;
|
|
type_init(name, type, kind, actual_bits, platform_target.floats[bits]);
|
|
}
|
|
|
|
void type_setup(PlatformTarget *target)
|
|
{
|
|
stable_init(&function_types, 0x1000);
|
|
max_alignment_vector = target->align_max_vector;
|
|
|
|
type_create_float("float16", &t.f16, TYPE_F16, BITS16);
|
|
type_create_float("float", &t.f32, TYPE_F32, BITS32);
|
|
type_create_float("double", &t.f64, TYPE_F64, BITS64);
|
|
type_create_float("float128", &t.f128, TYPE_F128, BITS128);
|
|
|
|
|
|
type_init_int("ichar", &t.i8, TYPE_I8, BITS8);
|
|
type_init_int("short", &t.i16, TYPE_I16, BITS16);
|
|
type_init_int("int", &t.i32, TYPE_I32, BITS32);
|
|
type_init_int("long", &t.i64, TYPE_I64, BITS64);
|
|
type_init_int("int128", &t.i128, TYPE_I128, BITS128);
|
|
|
|
type_init_int("bool", &t.u1, TYPE_BOOL, BITS8);
|
|
type_init_int("char", &t.u8, TYPE_U8, BITS8);
|
|
type_init_int("ushort", &t.u16, TYPE_U16, BITS16);
|
|
type_init_int("uint", &t.u32, TYPE_U32, BITS32);
|
|
type_init_int("ulong", &t.u64, TYPE_U64, BITS64);
|
|
type_init_int("uint128", &t.u128, TYPE_U128, BITS128);
|
|
|
|
type_init_int("void", &t.u0, TYPE_VOID, BITS8);
|
|
|
|
type_init("string", &t.str, TYPE_STRLIT, target->width_pointer, target->align_pointer);
|
|
|
|
|
|
type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 1, 1, 1);
|
|
type_create("complist", &t.ctlist, TYPE_UNTYPED_LIST, 1, 1, 1);
|
|
type_create("void!", &t.anyfail, TYPE_FAILABLE_ANY, 1, 1, 1);
|
|
type_init("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer);
|
|
|
|
type_init("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer);
|
|
create_type_cache(type_void);
|
|
type_void->type_cache[0] = &t.voidstar;
|
|
t.voidstar.pointer = type_void;
|
|
type_init("virtual*", &t.virtual, TYPE_VIRTUAL_ANY, target->width_pointer * 2, target->align_pointer);
|
|
type_init("virtual_generic", &t.virtual_generic, TYPE_VIRTUAL, target->width_pointer * 2, target->align_pointer);
|
|
|
|
|
|
type_create_alias("usize", &t.usz, type_int_unsigned_by_bitsize(target->width_pointer));
|
|
type_create_alias("isize", &t.isz, type_int_signed_by_bitsize(target->width_pointer));
|
|
|
|
type_create_alias("uptr", &t.uptr, type_int_unsigned_by_bitsize(target->width_pointer));
|
|
type_create_alias("iptr", &t.iptr, type_int_signed_by_bitsize(target->width_pointer));
|
|
|
|
type_create_alias("uptrdiff", &t.uptrdiff, type_int_unsigned_by_bitsize(target->width_pointer));
|
|
type_create_alias("iptrdiff", &t.iptrdiff, type_int_signed_by_bitsize(target->width_pointer));
|
|
|
|
alignment_subarray = MAX(type_abi_alignment(&t.voidstar), type_abi_alignment(t.usz.canonical));
|
|
size_subarray = alignment_subarray * 2;
|
|
type_init("anyerr", &t.anyerr, TYPE_ANYERR, target->width_pointer, target->align_pointer);
|
|
}
|
|
|
|
int type_kind_bitsize(TypeKind kind)
|
|
{
|
|
switch (kind)
|
|
{
|
|
case TYPE_I8:
|
|
case TYPE_U8:
|
|
return 8;
|
|
case TYPE_I16:
|
|
case TYPE_U16:
|
|
case TYPE_F16:
|
|
return 16;
|
|
case TYPE_I32:
|
|
case TYPE_U32:
|
|
case TYPE_F32:
|
|
return 32;
|
|
case TYPE_I64:
|
|
case TYPE_U64:
|
|
case TYPE_F64:
|
|
return 64;
|
|
case TYPE_I128:
|
|
case TYPE_U128:
|
|
case TYPE_F128:
|
|
return 128;
|
|
default:
|
|
UNREACHABLE;
|
|
}
|
|
}
|
|
bool type_is_scalar(Type *type)
|
|
{
|
|
RETRY:
|
|
switch (type->type_kind)
|
|
{
|
|
case CT_TYPES:
|
|
UNREACHABLE
|
|
case TYPE_VOID:
|
|
case TYPE_FUNC:
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
case TYPE_ARRAY:
|
|
case TYPE_SUBARRAY:
|
|
case TYPE_VECTOR:
|
|
case TYPE_FAILABLE_ANY:
|
|
return false;
|
|
case TYPE_BOOL:
|
|
case ALL_INTS:
|
|
case ALL_FLOATS:
|
|
case TYPE_STRLIT:
|
|
case TYPE_TYPEID:
|
|
case TYPE_POINTER:
|
|
case TYPE_ENUM:
|
|
case TYPE_ERRTYPE:
|
|
case TYPE_ANYERR:
|
|
case TYPE_VIRTUAL:
|
|
case TYPE_VIRTUAL_ANY:
|
|
return true;
|
|
case TYPE_BITSTRUCT:
|
|
type = type->decl->bitstruct.base_type->type;
|
|
goto RETRY;
|
|
case TYPE_DISTINCT:
|
|
type = type->decl->distinct_decl.base_type;
|
|
goto RETRY;
|
|
case TYPE_FAILABLE:
|
|
type = type->failable;
|
|
if (!type) return false;
|
|
goto RETRY;
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
goto RETRY;
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
/**
|
|
* Check if a type is contained in another type.
|
|
*
|
|
* @param type canonical type
|
|
* @param possible_subtype canonical type
|
|
* @return true if it is a subtype
|
|
*/
|
|
bool type_is_subtype(Type *type, Type *possible_subtype)
|
|
{
|
|
assert(type == type->canonical && possible_subtype == possible_subtype->canonical);
|
|
while (1)
|
|
{
|
|
if (type == possible_subtype) return true;
|
|
if (type->type_kind != possible_subtype->type_kind) return false;
|
|
if (type->decl->decl_kind != DECL_STRUCT) return false;
|
|
|
|
if (!possible_subtype->decl->strukt.members) return false;
|
|
|
|
Decl *first_element = possible_subtype->decl->strukt.members[0];
|
|
|
|
if (first_element->decl_kind != DECL_VAR) return false;
|
|
|
|
possible_subtype = first_element->type->canonical;
|
|
}
|
|
|
|
}
|
|
|
|
Type *type_from_token(TokenType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case TOKEN_ANYERR:
|
|
return type_anyerr;
|
|
case TOKEN_VOID:
|
|
return type_void;
|
|
case TOKEN_BOOL:
|
|
return type_bool;
|
|
case TOKEN_CHAR:
|
|
return type_char;
|
|
case TOKEN_DOUBLE:
|
|
return type_double;
|
|
case TOKEN_FLOAT:
|
|
return type_float;
|
|
case TOKEN_INT128:
|
|
return type_i128;
|
|
case TOKEN_ICHAR:
|
|
return type_ichar;
|
|
case TOKEN_INT:
|
|
return type_int;
|
|
case TOKEN_IPTR:
|
|
return type_iptr;
|
|
case TOKEN_IPTRDIFF:
|
|
return type_iptrdiff;
|
|
case TOKEN_ISIZE:
|
|
return type_isize;
|
|
case TOKEN_LONG:
|
|
return type_long;
|
|
case TOKEN_SHORT:
|
|
return type_short;
|
|
case TOKEN_UINT128:
|
|
return type_u128;
|
|
case TOKEN_UINT:
|
|
return type_uint;
|
|
case TOKEN_ULONG:
|
|
return type_ulong;
|
|
case TOKEN_UPTR:
|
|
return type_uptr;
|
|
case TOKEN_UPTRDIFF:
|
|
return type_uptrdiff;
|
|
case TOKEN_USHORT:
|
|
return type_ushort;
|
|
case TOKEN_USIZE:
|
|
return type_usize;
|
|
case TOKEN_TYPEID:
|
|
return type_typeid;
|
|
default:
|
|
UNREACHABLE
|
|
}
|
|
}
|
|
|
|
bool type_may_have_sub_elements(Type *type)
|
|
{
|
|
// An alias is not ok.
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_DISTINCT:
|
|
case TYPE_UNION:
|
|
case TYPE_STRUCT:
|
|
case TYPE_ENUM:
|
|
case TYPE_ERRTYPE:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Type *type_find_max_num_type(Type *num_type, Type *other_num)
|
|
{
|
|
TypeKind kind = num_type->type_kind;
|
|
TypeKind other_kind = other_num->type_kind;
|
|
assert(kind <= other_kind && "Expected ordering");
|
|
assert(kind != other_kind);
|
|
|
|
// 1. The only conversions need to happen if the other type is a number.
|
|
if (other_kind < TYPE_INTEGER_FIRST || other_kind > TYPE_FLOAT_LAST) return NULL;
|
|
|
|
// 2. First check the float case.
|
|
if (other_kind >= TYPE_FLOAT_FIRST && other_kind <= TYPE_FLOAT_LAST)
|
|
{
|
|
switch (other_kind)
|
|
{
|
|
case TYPE_F16:
|
|
case TYPE_F32:
|
|
case TYPE_F64:
|
|
case TYPE_F128:
|
|
// Pick the biggest, which will be in other_num due to ordering.
|
|
return other_num;
|
|
default:
|
|
UNREACHABLE
|
|
}
|
|
}
|
|
|
|
// Handle integer <=> integer conversions.
|
|
assert(type_kind_is_any_integer(other_kind) && type_is_integer(num_type));
|
|
|
|
// 4. Check the bit sizes.
|
|
unsigned other_bit_size = other_num->builtin.bitsize;
|
|
unsigned bit_size = num_type->builtin.bitsize;
|
|
|
|
// 5. The other type is unsigned
|
|
if (type_kind_is_unsigned(other_kind))
|
|
{
|
|
if (type_kind_is_signed(kind))
|
|
{
|
|
// 5a. Signed + Unsigned -> Signed
|
|
return bit_size >= other_bit_size ? num_type : type_int_signed_by_bitsize(other_bit_size);
|
|
}
|
|
// 5b. Unsigned + Unsigned -> return other_num which is the bigger due to ordering.
|
|
return other_num;
|
|
}
|
|
|
|
// 6. The other type is signed, then pick other_num which is bigger due to ordering.
|
|
return other_num;
|
|
}
|
|
|
|
/**
|
|
* max(Foo[:], Bar*) -> max(Foo*, Bar*)
|
|
* max(Foo[], Bar*) -> max(Foo*, Bar*)
|
|
* max(Foo[n]*, Bar*) -> max(Foo*, Bar*)
|
|
* max(void*, Foo*) -> void*
|
|
* max(Foo*, Bar*) -> max(Foo, Bar)*
|
|
* max(other, Foo*) -> NULL
|
|
*
|
|
* @param type
|
|
* @param other
|
|
* @return the max pointer type or NULL if none can be found.
|
|
*/
|
|
static inline Type *type_find_max_ptr_type(Type *type, Type *other)
|
|
{
|
|
// Subarray and vararray can implicitly convert to a pointer.
|
|
if (other->type_kind == TYPE_SUBARRAY)
|
|
{
|
|
Type *max_type = type_find_max_type(type->pointer, other->pointer);
|
|
if (!max_type) return NULL;
|
|
return type_get_ptr(max_type);
|
|
}
|
|
|
|
// Neither subarray, vararray or pointer? Then no max
|
|
if (other->type_kind != TYPE_POINTER) return NULL;
|
|
|
|
Type* other_pointer_type = other->pointer;
|
|
Type* pointer_type = type->pointer;
|
|
|
|
// Reorder if needed
|
|
if (other_pointer_type->type_kind < pointer_type->type_kind)
|
|
{
|
|
pointer_type = other_pointer_type;
|
|
other_pointer_type = type->pointer;
|
|
}
|
|
|
|
// void * is always max.
|
|
if (pointer_type->type_kind == TYPE_VOID) return type_voidptr;
|
|
|
|
if (pointer_type->type_kind == TYPE_POINTER && other_pointer_type->type_kind == TYPE_ARRAY)
|
|
{
|
|
// Decay foo[n]* to foo*
|
|
other_pointer_type = type_get_ptr(other_pointer_type->array.base);
|
|
}
|
|
|
|
Type *max_type = type_find_max_type(pointer_type, other_pointer_type);
|
|
if (!max_type) return NULL;
|
|
return type_get_ptr(max_type);
|
|
}
|
|
|
|
|
|
Type *type_find_max_type(Type *type, Type *other)
|
|
{
|
|
if (type == type_anyfail)
|
|
{
|
|
return type_get_opt_fail(other, true);
|
|
}
|
|
if (other == type_anyfail)
|
|
{
|
|
return type_get_failable(type);
|
|
}
|
|
|
|
type = type->canonical;
|
|
other = other->canonical;
|
|
|
|
assert(!type_is_failable(type) && !type_is_failable(other));
|
|
|
|
if (type == other) return type;
|
|
|
|
// Sort types
|
|
if (type->type_kind > other->type_kind)
|
|
{
|
|
Type *temp = type;
|
|
type = other;
|
|
other = temp;
|
|
}
|
|
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_INFERRED_ARRAY:
|
|
case TYPE_POISONED:
|
|
case TYPE_FAILABLE:
|
|
case TYPE_FAILABLE_ANY:
|
|
UNREACHABLE
|
|
case TYPE_VOID:
|
|
case TYPE_BOOL:
|
|
case TYPE_TYPEINFO:
|
|
case TYPE_VIRTUAL:
|
|
case TYPE_VIRTUAL_ANY:
|
|
case TYPE_BITSTRUCT:
|
|
return NULL;
|
|
case ALL_INTS:
|
|
if (other->type_kind == TYPE_DISTINCT && type_underlying_is_numeric(other)) return other;
|
|
if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical);
|
|
return type_find_max_num_type(type, other);
|
|
case ALL_FLOATS:
|
|
if (other->type_kind == TYPE_DISTINCT && type_is_float(other->decl->distinct_decl.base_type)) return other;
|
|
return type_find_max_num_type(type, other);
|
|
case TYPE_POINTER:
|
|
return type_find_max_ptr_type(type, other);
|
|
case TYPE_ENUM:
|
|
// IMPROVE: should there be implicit conversion between one enum and the other in
|
|
// some way?
|
|
return NULL;
|
|
case TYPE_ERRTYPE:
|
|
if (other->type_kind == TYPE_ERRTYPE) return type_anyerr;
|
|
return NULL;
|
|
case TYPE_FUNC:
|
|
case TYPE_UNION:
|
|
case TYPE_ANYERR:
|
|
case TYPE_TYPEID:
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNTYPED_LIST:
|
|
TODO
|
|
case TYPE_TYPEDEF:
|
|
UNREACHABLE
|
|
case TYPE_STRLIT:
|
|
if (other->type_kind == TYPE_DISTINCT)
|
|
{
|
|
// In this case we only react to the flattened type.
|
|
Type *flatten_other = type_flatten(other);
|
|
if (flatten_other->type_kind == TYPE_SUBARRAY && flatten_other->array.base->type_kind == TYPE_U8) return other;
|
|
if (flatten_other->type_kind == TYPE_POINTER && flatten_other->pointer->type_kind == TYPE_U8) return other;
|
|
}
|
|
if (other->type_kind == TYPE_SUBARRAY && other->array.base->type_kind == TYPE_U8) return other;
|
|
if (other->type_kind == TYPE_POINTER && other->pointer->type_kind == TYPE_U8) return other;
|
|
return NULL;
|
|
case TYPE_DISTINCT:
|
|
return NULL;
|
|
case TYPE_ARRAY:
|
|
return NULL;
|
|
case TYPE_SUBARRAY:
|
|
TODO
|
|
case TYPE_VECTOR:
|
|
// No implicit conversion between vectors
|
|
return NULL;
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
|
|
#define MAX_SEARCH_DEPTH 512
|
|
|
|
Type *type_find_common_ancestor(Type *left, Type *right)
|
|
{
|
|
if (left == right) return left;
|
|
left = left->canonical;
|
|
right = right->canonical;
|
|
if (left == right) return left;
|
|
if (left->type_kind != right->type_kind) return NULL;
|
|
if (left->type_kind == TYPE_POINTER)
|
|
{
|
|
Type *common = type_find_common_ancestor(left->pointer, right->pointer);
|
|
return common ? type_get_ptr(common) : NULL;
|
|
}
|
|
if (left->type_kind != TYPE_STRUCT) return NULL;
|
|
|
|
static Type *left_types[MAX_SEARCH_DEPTH];
|
|
int depth = 0;
|
|
while (depth < MAX_SEARCH_DEPTH)
|
|
{
|
|
if (!left->decl->strukt.members) break;
|
|
Decl *first_element = left->decl->strukt.members[0];
|
|
if (first_element->decl_kind != DECL_VAR) break;
|
|
if (first_element->type->canonical == right) return right;
|
|
left = first_element->type->canonical;
|
|
left_types[depth++] = left;
|
|
}
|
|
if (depth == MAX_SEARCH_DEPTH)
|
|
{
|
|
error_exit("Struct type depth %d exceeded.", MAX_SEARCH_DEPTH);
|
|
}
|
|
while (true)
|
|
{
|
|
if (!right->decl->strukt.members) return NULL;
|
|
Decl *first_element = right->decl->strukt.members[0];
|
|
if (first_element->decl_kind != DECL_VAR) return NULL;
|
|
right = first_element->type->canonical;
|
|
for (int i = 0; i < depth; i++)
|
|
{
|
|
if (right == left_types[i]) return right;
|
|
}
|
|
}
|
|
} |