Add macro arguments &foo $foo #foo.

C ABI compatibility aarch64, win64, x86, x64
Added debug info
This commit is contained in:
Christoffer Lerno
2020-10-19 20:58:40 +02:00
committed by Christoffer Lerno
parent 4222f2731e
commit 3c15e495dd
52 changed files with 7936 additions and 2113 deletions

View File

@@ -4,9 +4,9 @@
#include "compiler_internal.h"
static Type t_u0, t_str, t_u1, t_i8, t_i16, t_i32, t_i64, t_ixx;
static Type t_u8, t_u16, t_u32, t_u64;
static Type t_f32, t_f64, t_fxx;
static Type t_u0, t_str, t_u1, t_i8, t_i16, t_i32, t_i64, t_i128, t_ixx;
static Type t_u8, t_u16, t_u32, t_u64, t_u128;
static Type t_f16, t_f32, t_f64, t_f128, t_fxx;
static Type t_usz, t_isz;
static Type t_cus, t_cui, t_cul, t_cull;
static Type t_cs, t_ci, t_cl, t_cll;
@@ -16,19 +16,23 @@ Type *type_bool = &t_u1;
Type *type_void = &t_u0;
Type *type_string = &t_str;
Type *type_voidptr = &t_voidstar;
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_char = &t_i8;
Type *type_short = &t_i16;
Type *type_int = &t_i32;
Type *type_long = &t_i64;
Type *type_i128 = &t_i128;
Type *type_isize = &t_isz;
Type *type_byte = &t_u8;
Type *type_ushort = &t_u16;
Type *type_uint = &t_u32;
Type *type_ulong = &t_u64;
Type *type_u128 = &t_u128;
Type *type_usize = &t_usz;
Type *type_compint = &t_ixx;
Type *type_compfloat = &t_fxx;
@@ -52,7 +56,7 @@ unsigned alignment_error_code;
#define VAR_ARRAY_OFFSET 2
#define ARRAY_OFFSET 3
Type *type_signed_int_by_bitsize(unsigned bytesize)
Type *type_int_signed_by_bitsize(unsigned bytesize)
{
switch (bytesize)
{
@@ -60,10 +64,11 @@ Type *type_signed_int_by_bitsize(unsigned bytesize)
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", bytesize);
}
}
Type *type_unsigned_int_by_bitsize(unsigned bytesize)
Type *type_int_unsigned_by_bitsize(unsigned bytesize)
{
switch (bytesize)
{
@@ -71,6 +76,7 @@ Type *type_unsigned_int_by_bitsize(unsigned bytesize)
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);
}
}
@@ -87,18 +93,8 @@ const char *type_to_error_string(Type *type)
case TYPE_STRUCT:
case TYPE_VOID:
case TYPE_BOOL:
case TYPE_I8:
case TYPE_I16:
case TYPE_I32:
case TYPE_I64:
case TYPE_IXX:
case TYPE_U8:
case TYPE_U16:
case TYPE_U32:
case TYPE_U64:
case TYPE_F32:
case TYPE_F64:
case TYPE_FXX:
case ALL_INTS:
case ALL_FLOATS:
case TYPE_UNION:
case TYPE_ERRTYPE:
return type->name;
@@ -114,6 +110,9 @@ const char *type_to_error_string(Type *type)
return strcat_arena(buffer, ")");
}
case TYPE_COMPLEX:
case TYPE_VECTOR:
TODO
case TYPE_MEMBER:
return "member";
case TYPE_TYPEINFO:
@@ -174,6 +173,10 @@ size_t type_size(Type *type)
{
switch (type->type_kind)
{
case TYPE_VECTOR:
return type_size(type->vector.base) * type->vector.len;
case TYPE_COMPLEX:
return type_size(type->complex) * 2;
case TYPE_POISONED:
case TYPE_TYPEINFO:
case TYPE_MEMBER:
@@ -215,15 +218,389 @@ const char *type_generate_qname(Type *type)
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->canonical;
if (allow_array)
{
while (type->type_kind == TYPE_ARRAY)
{
if (type->array.len == 0) return true;
type = type->array.base->canonical;
}
}
return type_is_union_struct(type) && type_is_empty_union_struct(type, allow_array);
}
bool type_is_empty_union_struct(Type *type, bool allow_array)
{
if (!type_is_union_struct(type)) return false;
Decl **members = type->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;
}
Type *type_find_single_struct_element(Type *type)
{
if (!type_is_union_struct(type)) return NULL;
Type *found = NULL;
Decl **members = type->decl->strukt.members;
VECEACH(members, i)
{
// Ignore empty arrays
if (type_is_empty_field(members[i]->type, true)) continue;
// Already one element found, not single element.
if (found) return NULL;
Type *field_type = members[i]->type->canonical;
while (field_type->type_kind == TYPE_ARRAY)
{
if (field_type->array.len != 1) break;
field_type = field_type->array.base;
}
if (type_is_union_struct(field_type))
{
field_type = type_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;
}
static bool type_is_qpx_vector(Type *type)
{
if (build_target.abi != ABI_PPC64_SVR4 || !build_target.ppc64.has_qpx) return false;
type = type->canonical;
if (type->type_kind != TYPE_VECTOR) return false;
if (type->vector.len == 1) return false;
switch (type->vector.base->type_kind)
{
case TYPE_F64:
return type_size(type) >= 256 / 8;
case TYPE_F32:
return type_size(type) <= 128 / 8;
default:
return false;
}
}
bool type_is_abi_aggregate(Type *type)
{
switch (type->type_kind)
{
case TYPE_POISONED:
return false;
case TYPE_TYPEDEF:
return type_is_abi_aggregate(type->canonical);
case ALL_FLOATS:
case TYPE_VOID:
case ALL_INTS:
case TYPE_BOOL:
case TYPE_VARARRAY:
case TYPE_TYPEID:
case TYPE_POINTER:
case TYPE_ENUM:
case TYPE_FUNC:
case TYPE_STRING:
case TYPE_VECTOR:
return false;
case TYPE_ERRTYPE:
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_SUBARRAY:
case TYPE_ARRAY:
case TYPE_ERR_UNION:
case TYPE_COMPLEX:
return true;
case TYPE_TYPEINFO:
case TYPE_MEMBER:
UNREACHABLE
}
UNREACHABLE
}
bool type_is_homogenous_base_type(Type *type)
{
type = type->canonical;
switch (build_target.abi)
{
case ABI_PPC64_SVR4:
switch (type->type_kind)
{
case TYPE_F128:
if (!build_target.float_128) return false;
FALLTHROUGH;
case TYPE_F32:
case TYPE_F64:
return !build_target.ppc64.is_softfp;
case TYPE_VECTOR:
return type_size(type) == 128 / 8 || type_is_qpx_vector(type);
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:
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 (build_target.abi)
{
case ABI_PPC64_SVR4:
if (type->type_kind == TYPE_F128 && build_target.float_128) return members <= 8;
if (type->type_kind == TYPE_VECTOR) return members <= 8;
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
}
bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
{
*elements = 0;
switch (type->type_kind)
{
case TYPE_COMPLEX:
*base = type->complex;
*elements = 2;
break;
case TYPE_FXX:
case TYPE_POISONED:
case TYPE_IXX:
case TYPE_VOID:
case TYPE_TYPEINFO:
case TYPE_MEMBER:
case TYPE_TYPEID:
case TYPE_FUNC:
case TYPE_STRING:
case TYPE_SUBARRAY:
return false;
case TYPE_ERR_UNION:
*base = type_usize->canonical;
*elements = 2;
return true;
case TYPE_ERRTYPE:
*base = type_usize->canonical;
*elements = 1;
return true;
case TYPE_TYPEDEF:
return type_is_homogenous_aggregate(type->canonical, base, elements);
case TYPE_STRUCT:
case TYPE_UNION:
*elements = 0;
{
Decl **members = type->decl->strukt.members;
VECEACH(members, i)
{
unsigned member_mult = 1;
Type *member_type = members[i]->type->canonical;
while (member_type->type_kind == TYPE_ARRAY)
{
if (member_type->array.len == 0) return false;
member_mult *= member_type->array.len;
member_type = member_type->array.base;
}
unsigned member_members = 0;
if (type_is_empty_field(member_type, true)) continue;
if (!type_is_homogenous_aggregate(member_type, base, &member_members)) return false;
member_members *= member_mult;
if (type->type_kind == TYPE_UNION)
{
*elements = MAX(*elements, member_members);
}
else
{
*elements += member_members;
}
}
assert(base);
// Ensure no padding
if (type_size(*base) * *elements != type_size(type)) return false;
}
goto TYPECHECK;
case TYPE_ARRAY:
if (type->array.len == 0) return false;
if (!type_is_homogenous_aggregate(type->array.base, base, elements)) return false;
*elements *= type->array.len;
goto TYPECHECK;
case TYPE_ENUM:
// Lower enum to underlying type
type = type->decl->enums.type_info->type;
break;
case TYPE_BOOL:
// Lower bool to unsigned char
type = type_byte;
break;
case ALL_SIGNED_INTS:
// Lower signed to unsigned
type = type_int_unsigned_by_bitsize(type->builtin.bytesize);
break;
case ALL_UNSIGNED_INTS:
case ALL_REAL_FLOATS:
case TYPE_VECTOR:
break;
case TYPE_POINTER:
case TYPE_VARARRAY:
// All pointers are the same.
type = type_voidptr;
break;
}
*elements = 1;
if (!type_is_homogenous_base_type(type)) return false;
if (!*base)
{
*base = type;
// Special handling of non-power-of-2 vectors
if (type->type_kind == TYPE_VECTOR)
{
// Expand to actual size.
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);
}
unsigned int type_alloca_alignment(Type *type)
{
return type_abi_alignment(type);
}
Type *type_find_largest_union_element(Type *type)
{
assert(type->type_kind == TYPE_UNION);
size_t 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;
}
unsigned int type_abi_alignment(Type *type)
{
switch (type->type_kind)
{
case TYPE_POISONED:
case TYPE_VOID:
case TYPE_TYPEINFO:
case TYPE_MEMBER:
UNREACHABLE;
case TYPE_VECTOR:
case TYPE_COMPLEX:
TODO
case TYPE_VOID:
return 1;
case TYPE_TYPEDEF:
return type_abi_alignment(type->canonical);
case TYPE_ENUM:
@@ -232,7 +609,7 @@ unsigned int type_abi_alignment(Type *type)
return alignment_error_code;
case TYPE_STRUCT:
case TYPE_UNION:
return type->decl->strukt.abi_alignment;
return type->decl->alignment;
case TYPE_TYPEID:
case TYPE_BOOL:
case ALL_INTS:
@@ -252,12 +629,11 @@ unsigned int type_abi_alignment(Type *type)
UNREACHABLE
}
static inline void create_type_cache(Type *canonical_type)
static inline void create_type_cache(Type *type)
{
assert(canonical_type->canonical == canonical_type);
for (int i = 0; i < ARRAY_OFFSET; i++)
{
vec_add(canonical_type->type_cache, NULL);
vec_add(type->type_cache, NULL);
}
}
@@ -394,40 +770,61 @@ Type *type_get_indexed_type(Type *type)
}
Type *type_create_array(Type *arr_type, uint64_t len, bool canonical)
static Type *type_create_array(Type *element_type, uint64_t len, bool vector, bool canonical)
{
if (canonical) arr_type = arr_type->canonical;
if (!arr_type->type_cache)
if (canonical) element_type = element_type->canonical;
if (!element_type->type_cache)
{
create_type_cache(arr_type);
create_type_cache(element_type);
}
int entries = (int)vec_size(arr_type->type_cache);
int entries = (int)vec_size(element_type->type_cache);
for (int i = ARRAY_OFFSET; i < entries; i++)
{
Type *ptr = arr_type->type_cache[i];
if (ptr->array.len == len)
Type *ptr_vec = element_type->type_cache[i];
if (vector)
{
return ptr;
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 *array = type_new(TYPE_ARRAY, strformat("%s[%llu]", arr_type->name, len));
array->array.base = arr_type;
array->array.len = len;
if (arr_type->canonical == arr_type)
Type *vec_arr;
if (vector)
{
array->canonical = array;
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
{
array->canonical = type_create_array(arr_type, len, true);
vec_arr = type_new(TYPE_ARRAY, strformat("%s[%llu]", element_type->name, len));
vec_arr->array.base = element_type;
vec_arr->array.len = len;
}
VECADD(arr_type->type_cache, array);
return array;
if (element_type->canonical == element_type)
{
vec_arr->canonical = vec_arr;
}
else
{
vec_arr->canonical = type_create_array(element_type, len, vector, true);
}
VECADD(element_type->type_cache, vec_arr);
return vec_arr;
}
Type *type_get_array(Type *arr_type, uint64_t len)
{
return type_create_array(arr_type, len, false);
return type_create_array(arr_type, len, false, false);
}
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,
@@ -475,11 +872,13 @@ type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target-
DEF_TYPE(short, t_i16, TYPE_I16, 16, short);
DEF_TYPE(int, t_i32, TYPE_I32, 32, int);
DEF_TYPE(long, t_i64, TYPE_I64, 64, long);
DEF_TYPE(i128, t_i128, TYPE_I128, 128, i128);
DEF_TYPE(byte, t_u8, TYPE_U8, 8, byte);
DEF_TYPE(ushort, t_u16, TYPE_U16, 16, short);
DEF_TYPE(uint, t_u32, TYPE_U32, 32, int);
DEF_TYPE(ulong, t_u64, TYPE_U64, 64, long);
DEF_TYPE(u128, t_u128, TYPE_U128, 128, i128);
DEF_TYPE(void, t_u0, TYPE_VOID, 8, byte);
DEF_TYPE(string, t_str, TYPE_STRING, target->width_pointer, pointer);
@@ -495,18 +894,18 @@ type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target-
type_create("compint", &t_ixx, TYPE_IXX, 32, 0, 0);
type_create("compfloat", &t_fxx, TYPE_FXX, 64, 0, 0);
type_create_alias("usize", &t_usz, type_unsigned_int_by_bitsize(target->width_pointer));
type_create_alias("isize", &t_isz, type_signed_int_by_bitsize(target->width_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("c_ushort", &t_cus, type_unsigned_int_by_bitsize(target->width_c_short));
type_create_alias("c_uint", &t_cui, type_unsigned_int_by_bitsize(target->width_c_int));
type_create_alias("c_ulong", &t_cul, type_unsigned_int_by_bitsize(target->width_c_long));
type_create_alias("c_ulonglong", &t_cull, type_unsigned_int_by_bitsize(target->width_c_long_long));
type_create_alias("c_ushort", &t_cus, type_int_unsigned_by_bitsize(target->width_c_short));
type_create_alias("c_uint", &t_cui, type_int_unsigned_by_bitsize(target->width_c_int));
type_create_alias("c_ulong", &t_cul, type_int_unsigned_by_bitsize(target->width_c_long));
type_create_alias("c_ulonglong", &t_cull, type_int_unsigned_by_bitsize(target->width_c_long_long));
type_create_alias("c_short", &t_cs, type_signed_int_by_bitsize(target->width_c_short));
type_create_alias("c_int", &t_ci, type_signed_int_by_bitsize(target->width_c_int));
type_create_alias("c_long", &t_cl, type_signed_int_by_bitsize(target->width_c_long));
type_create_alias("c_longlong", &t_cll, type_signed_int_by_bitsize(target->width_c_long_long));
type_create_alias("c_short", &t_cs, type_int_signed_by_bitsize(target->width_c_short));
type_create_alias("c_int", &t_ci, type_int_signed_by_bitsize(target->width_c_int));
type_create_alias("c_long", &t_cl, type_int_signed_by_bitsize(target->width_c_long));
type_create_alias("c_longlong", &t_cll, type_int_signed_by_bitsize(target->width_c_long_long));
alignment_subarray = MAX(type_abi_alignment(&t_voidstar), type_abi_alignment(t_usz.canonical));
size_subarray = alignment_subarray * 2;
@@ -562,22 +961,27 @@ typedef enum
Type *type_find_max_num_type(Type *num_type, Type *other_num)
{
if (other_num->type_kind < TYPE_I8 || other_num->type_kind > TYPE_FXX) return NULL;
assert(num_type->type_kind >= TYPE_I8 && num_type->type_kind <= TYPE_FXX);
static MaxType max_conv[TYPE_FXX - TYPE_I8 + 1][TYPE_FXX - TYPE_BOOL + 1] = {
// I8 I16 I32 I64 U8 U16 U32 U64 IXX F32 F64 FXX
{ L, R, R, R, X, X, X, X, L, R, R, FL }, // I8
{ L, L, R, R, L, X, X, X, L, R, R, FL }, // I16
{ L, L, L, R, L, L, X, X, L, R, R, FL }, // I32
{ L, L, L, L, L, L, L, X, L, R, R, FL }, // I64
{ X, R, R, R, L, R, R, R, L, R, R, FL }, // U8
{ X, X, R, R, L, L, R, R, L, R, R, FL }, // U16
{ X, X, X, R, L, L, L, R, L, R, R, FL }, // U32
{ X, X, X, X, L, L, L, L, L, R, R, FL }, // U64
{ R, R, R, R, R, R, R, R, L, R, R, R }, // IXX
{ L, L, L, L, L, L, L, L, L, L, R, L }, // F32
{ L, L, L, L, L, L, L, L, L, L, L, L }, // F64
{ FL, FL, FL, FL, FL, FL, FL, FL, FL, R, R, L }, // FXX
TypeKind kind = num_type->type_kind;
TypeKind other_kind = other_num->type_kind;
if (other_kind < TYPE_I8 || other_kind > TYPE_FXX) return NULL;
static MaxType max_conv[TYPE_FXX - TYPE_I8 + 1][TYPE_FXX - TYPE_I8 + 1] = {
// I8 I16 I32 I64 I128 U8 U16 U32 U64 U128 IXX F16 F32 F64 F128 FXX
{ L, R, R, R, R, X, X, X, X, X, L, R, R, R, R, FL }, // I8
{ L, L, R, R, R, L, X, X, X, X, L, R, R, R, R, FL }, // I16
{ L, L, L, R, R, L, L, X, X, X, L, R, R, R, R, FL }, // I32
{ L, L, L, L, R, L, L, L, X, X, L, R, R, R, R, FL }, // I64
{ L, L, L, L, L, L, L, L, X, X, L, R, R, R, R, FL }, // I128
{ X, R, R, R, R, L, R, R, R, R, L, R, R, R, R, FL }, // U8
{ X, X, R, R, R, L, L, R, R, R, L, R, R, R, R, FL }, // U16
{ X, X, X, R, R, L, L, L, R, R, L, R, R, R, R, FL }, // U32
{ X, X, X, X, R, L, L, L, L, R, L, R, R, R, R, FL }, // U64
{ X, X, X, X, X, L, L, L, L, L, L, R, R, R, R, FL }, // U128
{ R, R, R, R, R, R, R, R, R, R, L, R, R, R, R, R }, // IXX
{ L, L, L, L, L, L, L, L, L, L, L, L, R, R, R, L }, // F16
{ L, L, L, L, L, L, L, L, L, L, L, L, L, R, R, L }, // F32
{ L, L, L, L, L, L, L, L, L, L, L, L, L, L, R, L }, // F64
{ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L }, // F128
{ FL, FL, FL, FL, FL, FL, FL, FL, FL, FL, FL, R, R, R, R, L }, // FXX
};
MaxType conversion = max_conv[num_type->type_kind - TYPE_I8][other_num->type_kind - TYPE_I8];
switch (conversion)
@@ -700,20 +1104,10 @@ Type *type_find_max_type(Type *type, Type *other)
case TYPE_TYPEINFO:
case TYPE_MEMBER:
return NULL;
case TYPE_I8:
case TYPE_I16:
case TYPE_I32:
case TYPE_I64:
case TYPE_IXX:
case TYPE_U8:
case TYPE_U16:
case TYPE_U32:
case TYPE_U64:
case ALL_INTS:
if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical);
FALLTHROUGH;
case TYPE_F32:
case TYPE_F64:
case TYPE_FXX:
case ALL_FLOATS:
return type_find_max_num_type(type, other);
case TYPE_POINTER:
return type_find_max_ptr_type(type, other);
@@ -741,6 +1135,12 @@ Type *type_find_max_type(Type *type, Type *other)
return type_find_max_vararray_type(type, other);
case TYPE_SUBARRAY:
TODO
case TYPE_VECTOR:
// No implicit conversion between vectors
return NULL;
case TYPE_COMPLEX:
// Implicit conversion or not?
TODO;
}
UNREACHABLE
}