Added vector dot functions. Comparison now yields bool vector. Cast between vector types.

This commit is contained in:
Christoffer Lerno
2022-12-16 17:15:28 +01:00
committed by Christoffer Lerno
parent 8008fb2c18
commit c339261d1e
16 changed files with 365 additions and 20 deletions

View File

@@ -2308,6 +2308,7 @@ bool type_is_user_defined(Type *type);
bool type_is_structurally_equivalent(Type *type1, Type *type);
bool type_flat_is_floatlike(Type *type);
bool type_flat_is_intlike(Type *type);
bool type_flat_is_boolintlike(Type *type);
bool type_flat_is_numlike(Type *type);
bool type_may_have_sub_elements(Type *type);
bool type_may_have_method(Type *type);
@@ -2327,6 +2328,7 @@ INLINE bool type_is_substruct(Type *type);
INLINE Type *type_flatten_for_bitstruct(Type *type);
INLINE const char *type_invalid_storage_type_name(Type *type);
INLINE bool type_is_float(Type *type);
INLINE bool type_is_floatlike(Type *type);
INLINE bool type_is_optional(Type *type);
INLINE bool type_is_optional_type(Type *type);
INLINE bool type_is_optional_any(Type *type);
@@ -2577,6 +2579,14 @@ INLINE bool type_is_float(Type *type)
return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST;
}
INLINE bool type_is_floatlike(Type *type)
{
type = type->canonical;
TypeKind kind = type->type_kind;
if (kind == TYPE_VECTOR && type_is_float(type->array.base)) return true;
return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST;
}
INLINE const char *type_invalid_storage_type_name(Type *type)
{
switch (type->type_kind)
@@ -2638,9 +2648,9 @@ INLINE Type *type_new(TypeKind kind, const char *name)
INLINE bool type_convert_will_trunc(Type *destination, Type *source)
{
assert(type_is_builtin(destination->canonical->type_kind));
assert(type_is_builtin(source->canonical->type_kind));
return (unsigned)destination->canonical->builtin.bitsize < (unsigned)source->canonical->builtin.bitsize;
assert(type_flat_is_vector(destination) || type_is_builtin(destination->canonical->type_kind));
assert(type_flat_is_vector(destination) || type_is_builtin(source->canonical->type_kind));
return type_size(destination) < type_size(source);
}
@@ -2786,6 +2796,17 @@ INLINE bool type_flat_is_vector(Type *type)
return type_flatten(type)->type_kind == TYPE_VECTOR;
}
INLINE bool type_kind_is_any_vector(TypeKind kind)
{
return kind == TYPE_VECTOR || kind == TYPE_INFERRED_VECTOR || kind == TYPE_SCALED_VECTOR;
}
INLINE bool type_flat_is_bool_vector(Type *type)
{
Type *flat = type_flatten(type);
return flat->type_kind == TYPE_VECTOR && type_flatten(flat->array.base) == type_bool;
}
INLINE bool type_is_union_or_strukt(Type *type)
{
DECL_TYPE_KIND_REAL(kind, type);

View File

@@ -95,6 +95,7 @@ typedef enum
CAST_PTRBOOL,
CAST_BOOLINT,
CAST_BOOLFP,
CAST_BOOLVECINT,
CAST_BOOLBOOL,
CAST_FPBOOL,
CAST_INTBOOL,

View File

@@ -369,6 +369,7 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_
case CAST_STST:
case CAST_VECARR:
case CAST_ARRVEC:
case CAST_BOOLVECINT:
if (eval_kind != CONSTANT_EVAL_NO_SIDE_EFFECTS) return false;
return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind);
case CAST_XIPTR:

View File

@@ -771,15 +771,9 @@ void llvm_set_linkage(GenContext *c, Decl *decl, LLVMValueRef value)
LLVMSetLinkage(value, LLVMLinkerPrivateLinkage);
break;
}
}
void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value)
{
value->value = llvm_value;
@@ -788,6 +782,14 @@ void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value)
value->type = type_bool;
}
void llvm_value_set_bool_vector(BEValue *value, LLVMValueRef llvm_value, Type *type)
{
value->value = llvm_value;
value->alignment = type_abi_alignment(type);
value->kind = BE_BOOLVECTOR;
value->type = type;
}
void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i)
{
llvm_value_set(value, llvm_const_int(c, type, i), type);

View File

@@ -481,7 +481,7 @@ static void llvm_emit_veccomp(GenContext *c, BEValue *value, Expr *expr, Builtin
}
else
{
bool is_signed = type_is_signed(value->type);
bool is_signed = type_is_signed(args[0]->type);
switch (fn)
{
case BUILTIN_VECCOMPEQ:
@@ -508,9 +508,7 @@ static void llvm_emit_veccomp(GenContext *c, BEValue *value, Expr *expr, Builtin
UNREACHABLE
}
}
Type *result_type = type_get_vector_bool(value->type);
res = LLVMBuildSExt(c->builder, res, llvm_get_type(c, result_type), "");
llvm_value_set(value, res, result_type);
llvm_value_set_bool_vector(value, res, expr->type);
return;
}

View File

@@ -1164,6 +1164,15 @@ void llvm_emit_array_to_vector_cast(GenContext *c, BEValue *value, Type *to_type
llvm_value_set(value, vector, to_type);
}
void llvm_emit_bool_to_intvec_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type)
{
llvm_value_rvalue(c, value);
LLVMTypeRef type = llvm_get_type(c, to_type);
LLVMValueRef res = LLVMBuildSExt(c->builder, value->value, type, "");
llvm_value_set(value, res, to_type);
}
void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *value, Type *to_type, Type *from_type)
{
Type *to_type_original = to_type;
@@ -1172,6 +1181,9 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu
switch (cast_kind)
{
case CAST_BOOLVECINT:
llvm_emit_bool_to_intvec_cast(c, value, to_type, from_type);
return;
case CAST_ARRVEC:
llvm_emit_array_to_vector_cast(c, value, to_type, from_type);
return;
@@ -1304,7 +1316,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu
case CAST_INTBOOL:
llvm_value_rvalue(c, value);
value->value = LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, from_type), "intbool");
value->kind = BE_BOOLEAN;
value->kind = type_kind_is_any_vector(value->type->type_kind) ? BE_BOOLVECTOR : BE_BOOLEAN;
break;
case CAST_FPFP:
llvm_value_rvalue(c, value);

View File

@@ -22,6 +22,7 @@ typedef enum
BE_ADDRESS,
BE_ADDRESS_FAILABLE,
BE_BOOLEAN,
BE_BOOLVECTOR,
} BackendValueKind;
typedef struct
@@ -258,6 +259,7 @@ static inline bool llvm_value_is_bool(BEValue *value) { return value->kind == BE
bool llvm_value_is_const(BEValue *value);
void llvm_value_rvalue(GenContext *context, BEValue *value);
void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value);
void llvm_value_set_bool_vector(BEValue *value, LLVMValueRef llvm_value, Type *type);
void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type);
void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i);
void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type, AlignSize alignment);

View File

@@ -102,6 +102,11 @@ INLINE LLVMValueRef llvm_emit_lshr(GenContext *c, LLVMValueRef value, LLVMValueR
INLINE LLVMValueRef llvm_emit_trunc_bool(GenContext *c, LLVMValueRef value)
{
LLVMTypeRef type = LLVMTypeOf(value);
if (LLVMGetTypeKind(type) == LLVMVectorTypeKind)
{
return LLVMBuildTrunc(c->builder, value, LLVMVectorType(c->bool_type, LLVMGetVectorSize(type)), "");
}
return LLVMBuildTrunc(c->builder, value, c->bool_type, "");
}

View File

@@ -30,6 +30,10 @@ LLVMValueRef llvm_store_to_ptr_aligned(GenContext *c, LLVMValueRef destination,
}
switch (value->kind)
{
case BE_BOOLVECTOR:
value->value = LLVMBuildSExt(c->builder, value->value, llvm_get_type(c, value->type), "");
value->kind = BE_VALUE;
return llvm_store_to_ptr_raw_aligned(c, destination, value->value, alignment);
case BE_BOOLEAN:
value->value = LLVMBuildZExt(c->builder, value->value, c->byte_type, "");
value->kind = BE_VALUE;
@@ -85,6 +89,7 @@ LLVMValueRef llvm_load_value(GenContext *c, BEValue *value)
llvm_value_fold_optional(c, value);
switch (value->kind)
{
case BE_BOOLVECTOR:
case BE_BOOLEAN:
case BE_VALUE:
return value->value;
@@ -99,6 +104,10 @@ LLVMValueRef llvm_load_value(GenContext *c, BEValue *value)
LLVMValueRef llvm_load_value_store(GenContext *c, BEValue *value)
{
LLVMValueRef val = llvm_load_value(c, value);
if (value->kind == BE_BOOLVECTOR)
{
return LLVMBuildSExt(c->builder, val, llvm_get_type(c, type_get_vector_bool(value->type)), "");
}
if (value->kind != BE_BOOLEAN) return val;
return LLVMBuildZExt(c->builder, val, c->byte_type, "");
}

View File

@@ -50,9 +50,14 @@ void llvm_value_rvalue(GenContext *c, BEValue *value)
{
if (value->type->type_kind == TYPE_BOOL && value->kind != BE_BOOLEAN)
{
value->value = LLVMBuildTrunc(c->builder, value->value, c->bool_type, "");
value->value = llvm_emit_trunc_bool(c, value->value);
value->kind = BE_BOOLEAN;
}
if (type_flat_is_bool_vector(value->type) && value->kind != BE_BOOLVECTOR)
{
value->value = llvm_emit_trunc_bool(c, value->value);
value->kind = BE_BOOLVECTOR;
}
return;
}
llvm_value_fold_optional(c, value);
@@ -67,6 +72,12 @@ void llvm_value_rvalue(GenContext *c, BEValue *value)
value->kind = BE_BOOLEAN;
return;
}
if (type_flat_is_bool_vector(value->type))
{
value->value = llvm_emit_trunc_bool(c, value->value);
value->kind = BE_BOOLVECTOR;
return;
}
value->kind = BE_VALUE;
}

View File

@@ -14,6 +14,7 @@ typedef enum
BA_FLOAT,
BA_INTLIKE,
BA_NUMLIKE,
BA_BOOLINTVEC,
BA_INTVEC,
BA_FLOATVEC,
BA_VEC,
@@ -109,12 +110,21 @@ static bool sema_check_builtin_args(Expr **args, BuiltinArg *arg_type, size_t ar
}
break;
case BA_INTVEC:
if (type->type_kind != TYPE_VECTOR || !type_flat_is_intlike(type->array.base))
{
SEMA_ERROR(args[i], "Expected an integer vector.");
return false;
}
break;
case BA_BOOLINTVEC:
if (type->type_kind != TYPE_VECTOR || !type_flat_is_boolintlike(type->array.base))
{
SEMA_ERROR(args[i], "Expected a boolean or integer vector.");
return false;
}
break;
case BA_FLOATVEC:
if (type->type_kind != TYPE_VECTOR || !type_flat_is_floatlike(type->array.base))
{
@@ -326,7 +336,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
(BuiltinArg[]) { BA_VEC, BA_VEC },
arg_count)) return false;
if (!sema_check_builtin_args_match(args, 2)) return false;
rtype = type_get_vector_bool(args[0]->type);
rtype = type_get_vector(type_bool, type_flatten(args[0]->type)->array.len);
break;
case BUILTIN_OVERFLOW_ADD:
case BUILTIN_OVERFLOW_MUL:
@@ -492,7 +502,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
case BUILTIN_REDUCE_XOR:
case BUILTIN_REDUCE_MUL:
if (!sema_check_builtin_args(args,
(BuiltinArg[]) { BA_INTVEC },
(BuiltinArg[]) { BA_BOOLINTVEC },
arg_count)) return false;
rtype = args[0]->type->canonical->array.base;
break;

View File

@@ -14,6 +14,7 @@ static Expr *recursive_may_narrow_int(Expr *expr, Type *type);
static void recursively_rewrite_untyped_list(Expr *expr, Expr **list);
static inline bool cast_may_implicit_ptr(Type *from_pointee, Type *to_pointee);
static inline bool cast_may_array(Type *from, Type *to, bool is_explicit);
static inline bool cast_may_vector(Type *from, Type *to, bool is_explicit, bool is_const, CastOption option);
static inline bool insert_cast(Expr *expr, CastKind kind, Type *type)
{
@@ -468,6 +469,10 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability,
// 2. Same underlying type, always ok
if (from_type == to_type) return true;
if (type_kind_is_any_vector(to_type->type_kind) && type_kind_is_any_vector(from_type->type_kind))
{
return cast_may_vector(from_type, to_type, true, is_const, CAST_OPTION_NONE);
}
if (type_is_any_arraylike(to_type) && type_is_any_arraylike(from_type))
{
return cast_may_array(from_type, to_type, true);
@@ -568,6 +573,24 @@ bool type_may_convert_to_anyerr(Type *type)
return type->failable->canonical == type_void;
}
static inline bool cast_may_vector(Type *from, Type *to, bool is_explicit, bool is_const, CastOption option)
{
if (to->array.len != from->array.len) return false;
Type *to_inner = to->array.base;
Type *from_inner = from->array.base;
if (is_explicit)
{
to_inner = type_flatten(to_inner);
from_inner = type_flatten(from_inner);
}
if (to_inner == from_inner) return true;
if (from_inner == type_bool && type_is_integer(to_inner)) return true;
if (is_explicit)
{
return cast_may_explicit(from_inner, to_inner, true, is_const);
}
return cast_may_implicit(from_inner, to_inner, option);
}
static inline bool cast_may_array(Type *from, Type *to, bool is_explicit)
{
@@ -807,6 +830,11 @@ bool cast_may_implicit(Type *from_type, Type *to_type, CastOption option)
return false;
}
if (type_kind_is_any_vector(to->type_kind) && to->type_kind == from->type_kind)
{
return cast_may_vector(from, to, false, false, option);
}
if (type_is_any_arraylike(to) && type_is_any_arraylike(from))
{
return cast_may_array(from, to, false);
@@ -1439,6 +1467,101 @@ static bool vec_to_arr(Expr *expr, Type *to_type)
return true;
}
static void vec_const_init_to_type(ConstInitializer *initializer, Type *to_type)
{
switch (initializer->kind)
{
case CONST_INIT_ARRAY:
{
Type *element_type = type_flatten(to_type)->array.base;
FOREACH_BEGIN(ConstInitializer *element, initializer->init_array.elements)
vec_const_init_to_type(element, element_type);
FOREACH_END();
break;
}
case CONST_INIT_ARRAY_FULL:
{
Type *element_type = type_flatten(to_type)->array.base;
FOREACH_BEGIN(ConstInitializer *element, initializer->init_array_full)
vec_const_init_to_type(element, element_type);
FOREACH_END();
break;
}
case CONST_INIT_VALUE:
{
Type *to_flat = type_flatten(to_type);
bool is_neg_conversion = to_flat && type_flatten(initializer->type) == type_bool;
if (is_neg_conversion)
{
bool is_true = initializer->init_value->const_expr.b;
initializer->init_value->const_expr.ixx = (Int)
{ .i = is_true ? (Int128) { UINT64_MAX, UINT64_MAX } : (Int128) { 0, 0 },
.type = to_flat->type_kind };
initializer->init_value->type = to_type;
}
else
{
cast(initializer->init_value, to_type);
}
break;
}
case CONST_INIT_ZERO:
break;
case CONST_INIT_UNION:
case CONST_INIT_STRUCT:
UNREACHABLE
case CONST_INIT_ARRAY_VALUE:
vec_const_init_to_type(initializer->init_array_value.element, to_type);
break;
}
initializer->type = to_type;
}
static bool vec_to_vec(Expr *expr, Type *to_type)
{
if (expr->expr_kind != EXPR_CONST)
{
Type *from_type = type_flatten(expr->type);
Type *from_element = from_type->array.base;
to_type = type_flatten(to_type);
Type *to_element = to_type->array.base;
if (type_is_float(from_element))
{
if (to_element == type_bool) return insert_cast(expr, CAST_FPBOOL, to_type);
if (type_is_unsigned(to_element)) return insert_cast(expr, CAST_FPUI, to_type);
if (type_is_signed(to_element)) return insert_cast(expr, CAST_FPSI, to_type);
if (type_is_float(to_element)) return insert_cast(expr, CAST_FPFP, to_type);
UNREACHABLE;
}
if (from_element == type_bool)
{
if (type_is_integer(to_element)) return insert_cast(expr, CAST_BOOLVECINT, to_type);
if (type_is_float(to_element)) return insert_cast(expr, CAST_FPFP, to_type);
UNREACHABLE;
}
if (type_is_signed(from_element))
{
if (to_element == type_bool) return insert_cast(expr, CAST_INTBOOL, to_type);
if (type_is_unsigned(to_element)) return insert_cast(expr, CAST_SIUI, to_type);
if (type_is_signed(to_element)) return insert_cast(expr, CAST_SISI, to_type);
if (type_is_float(to_element)) return insert_cast(expr, CAST_SIFP, to_type);
UNREACHABLE
}
assert(type_is_unsigned(from_element));
if (to_element == type_bool) return insert_cast(expr, CAST_INTBOOL, to_type);
if (type_is_unsigned(to_element)) return insert_cast(expr, CAST_UIUI, to_type);
if (type_is_signed(to_element)) return insert_cast(expr, CAST_UISI, to_type);
if (type_is_float(to_element)) return insert_cast(expr, CAST_UIFP, to_type);
UNREACHABLE
}
assert(expr->const_expr.const_kind == CONST_INITIALIZER);
ConstInitializer *list = expr->const_expr.initializer;
vec_const_init_to_type(list, to_type);
expr->type = to_type;
return true;
}
static bool err_to_anyerr(Expr *expr, Type *to_type)
{
expr->type = to_type;
@@ -1587,6 +1710,7 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type)
break;
case TYPE_VECTOR:
if (to->type_kind == TYPE_ARRAY) return vec_to_arr(expr, to_type);
if (to->type_kind == TYPE_VECTOR) return vec_to_vec(expr, to_type);
break;
}
UNREACHABLE

View File

@@ -351,6 +351,14 @@ bool type_flat_is_intlike(Type *type)
return kind >= TYPE_INTEGER_FIRST && kind <= TYPE_INTEGER_LAST;
}
bool type_flat_is_boolintlike(Type *type)
{
type = type_flatten(type);
if (type->type_kind == TYPE_VECTOR) type = type->array.base;
TypeKind kind = type->type_kind;
return kind == TYPE_BOOL || (kind >= TYPE_INTEGER_FIRST && kind <= TYPE_INTEGER_LAST);
}
bool type_is_int128(Type *type)
{