diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index b6534d907..044994def 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1867,6 +1867,7 @@ static inline bool expr_is_init_list(Expr *expr) ExprKind kind = expr->expr_kind; return kind == EXPR_DESIGNATED_INITIALIZER_LIST || kind == EXPR_INITIALIZER_LIST; } +bool float_const_fits_type(const ExprConst *expr_const, TypeKind kind); #pragma mark --- Lexer functions diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 099c903de..647bfdaaa 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -95,6 +95,7 @@ typedef enum CAST_PTRPTR, CAST_PTRXI, CAST_ARRPTR, + CAST_ARRVEC, CAST_STRPTR, CAST_PTRBOOL, CAST_BOOLINT, diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 1e7290b04..c838d8216 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -34,6 +34,18 @@ static inline LLVMValueRef llvm_emit_extract_value(GenContext *c, LLVMValueRef a } } +static inline LLVMValueRef llvm_emit_extract_element(GenContext *c, LLVMValueRef vector, unsigned index) +{ + if (LLVMIsConstant(vector)) + { + return LLVMConstExtractElement(vector, llvm_const_int(c, type_usize, index)); + } + else + { + return LLVMBuildExtractElement(c->builder, vector, llvm_const_int(c, type_usize, index), ""); + } +} + static inline LLVMValueRef llvm_emit_insert_value(GenContext *c, LLVMValueRef agg, LLVMValueRef new_value, unsigned index) { if (LLVMIsConstant(agg) && LLVMIsConstant(new_value)) @@ -1021,6 +1033,43 @@ LLVMValueRef gencontext_emit_value_bitcast(GenContext *context, LLVMValueRef val return gencontext_emit_load(context, to_type, ptr_cast); } +void llvm_emit_vector_to_array_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type) +{ + llvm_value_rvalue(c, value); + LLVMTypeRef array_type = llvm_get_type(c, to_type); + LLVMValueRef array = LLVMGetUndef(array_type); + bool is_const = LLVMIsConstant(value->value); + for (unsigned i = 0; i < to_type->array.len; i++) + { + LLVMValueRef element = llvm_emit_extract_element(c, value->value, i); + if (is_const) + { + array = LLVMConstInsertValue(array, element, &i, 1); + continue; + } + array = LLVMBuildInsertValue(c->builder, array, element, i, ""); + } + llvm_value_set(value, array, to_type); +} + +void llvm_emit_array_to_vector_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type) +{ + llvm_value_rvalue(c, value); + LLVMTypeRef vector_type = llvm_get_type(c, to_type); + LLVMValueRef vector = LLVMGetUndef(vector_type); + bool is_const = LLVMIsConstant(value->value); + for (unsigned i = 0; i < to_type->vector.len; i++) + { + LLVMValueRef element = llvm_emit_extract_value(c, value->value, i); + if (is_const) + { + vector = LLVMConstInsertElement(vector, element, llvm_const_int(c, type_usize, i)); + continue; + } + vector = LLVMBuildInsertElement(c->builder, vector, element, llvm_const_int(c, type_usize, i), ""); + } + llvm_value_set(value, vector, to_type); +} void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_type, Type *from_type) { @@ -1029,6 +1078,9 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ switch (cast_kind) { + case CAST_ARRVEC: + llvm_emit_array_to_vector_cast(c, value, to_type, from_type); + return; case CAST_PTRANY: { llvm_value_rvalue(c, value); @@ -1130,7 +1182,8 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ assert(type_lowering(to_type) == type_lowering(from_type)); break; case CAST_VECARR: - TODO + llvm_emit_vector_to_array_cast(c, value, to_type, from_type); + break; case CAST_EUER: TODO // gencontext_emit_value_bitcast(c, value->value, to_type, from_type); case CAST_ERBOOL: diff --git a/src/compiler/number.c b/src/compiler/number.c index 6c5e2b8f2..7926fc4f3 100644 --- a/src/compiler/number.c +++ b/src/compiler/number.c @@ -4,6 +4,9 @@ #include "compiler_internal.h" +#define FLOAT32_LIMIT 340282346638528859811704183484516925440.0000000000000000 +#define FLOAT64_LIMIT 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0000000000000000 +#define FLOAT16_LIMIT 65504 void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind) { @@ -160,6 +163,32 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp return (op == BINARYOP_EQ) && is_eq; } +bool float_const_fits_type(const ExprConst *expr_const, TypeKind kind) +{ + Real hi_limit; + Real lo_limit; + switch (kind) + { + case TYPE_F16: + lo_limit = hi_limit = FLOAT16_LIMIT; + break; + case TYPE_F32: + lo_limit = hi_limit = FLOAT32_LIMIT; + break; + case TYPE_F64: + lo_limit = hi_limit = FLOAT64_LIMIT; + break; + case TYPE_F128: + // Assume this to be true + return true; + case TYPE_BOOL: + return true; + default: + UNREACHABLE + } + return expr_const->fxx.f >= -lo_limit && expr_const->fxx.f <= hi_limit; +} + bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind) { switch (kind) @@ -167,11 +196,10 @@ bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind) case ALL_INTS: return !int_fits(expr->ixx, kind); case TYPE_F16: - REMINDER("Check f16 narrowing"); - FALLTHROUGH; case TYPE_F32: case TYPE_F64: case TYPE_F128: + return !float_const_fits_type(expr, kind); case TYPE_BOOL: return false; default: diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index d108ee8d5..d1827cfe2 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -7,9 +7,7 @@ #pragma clang diagnostic push #pragma ide diagnostic ignored "ConstantFunctionResult" -#define FLOAT32_LIMIT 340282346638528859811704183484516925440.0000000000000000 -#define FLOAT64_LIMIT 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0000000000000000 -#define FLOAT16_LIMIT 65504 + static bool bitstruct_cast(Expr *expr, Type *from_type, Type *to, Type *to_type); static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *to_type); @@ -671,29 +669,7 @@ bool cast_may_implicit(Type *from_type, Type *to_type, bool is_simple_expr, bool bool may_convert_float_const_implicit(Expr *expr, Type *to_type) { - Type *to_type_flat = type_flatten(to_type); - Real hi_limit; - Real lo_limit; - switch (to_type_flat->type_kind) - { - case TYPE_F16: - lo_limit = hi_limit = FLOAT16_LIMIT; - break; - case TYPE_F32: - lo_limit = hi_limit = FLOAT32_LIMIT; - break; - case TYPE_F64: - lo_limit = hi_limit = FLOAT64_LIMIT; - break; - case TYPE_F128: - // Assume this to be true - return true; - case TYPE_BOOL: - return true; - default: - UNREACHABLE - } - if (expr->const_expr.fxx.f < -lo_limit || expr->const_expr.fxx.f > hi_limit) + if (!float_const_fits_type(&expr->const_expr, type_flatten(to_type)->type_kind)) { #if LONG_DOUBLE SEMA_ERROR(expr, "The value '%Lg' is out of range for %s, so you need an explicit cast to truncate the value.", expr->const_expr.fxx.f, type_quoted_error_string(to_type)); @@ -705,32 +681,6 @@ bool may_convert_float_const_implicit(Expr *expr, Type *to_type) return true; } -bool float_const_fits_type(Expr *expr, Type *to_type) -{ - Type *to_type_flat = type_flatten(to_type); - Real hi_limit; - Real lo_limit; - switch (to_type_flat->type_kind) - { - case TYPE_F16: - lo_limit = hi_limit = FLOAT16_LIMIT; - break; - case TYPE_F32: - lo_limit = hi_limit = FLOAT32_LIMIT; - break; - case TYPE_F64: - lo_limit = hi_limit = FLOAT64_LIMIT; - break; - case TYPE_F128: - // Assume this to be true - return true; - case TYPE_BOOL: - return true; - default: - UNREACHABLE - } - return expr->const_expr.fxx.f >= -lo_limit && expr->const_expr.fxx.f <= hi_limit; -} bool may_convert_int_const_implicit(Expr *expr, Type *to_type) { @@ -844,7 +794,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type) return type_size(expr->type) > type_size(type) ? expr : NULL; } assert(expr->const_expr.const_kind == CONST_FLOAT); - if (!float_const_fits_type(expr, type_flatten(type))) + if (!float_const_fits_type(&expr->const_expr, type_flatten(type)->type_kind)) { return expr; } @@ -1290,9 +1240,12 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) if (to == type_bool) return err_to_bool(expr, to_type); if (type_is_integer(to)) return insert_cast(expr, CAST_ERINT, to_type); break; + case TYPE_ARRAY: + if (to->type_kind == TYPE_VECTOR) return insert_cast(expr, CAST_ARRVEC, to_type); + FALLTHROUGH; case TYPE_STRUCT: case TYPE_UNION: - case TYPE_ARRAY: + if (to->type_kind == TYPE_ARRAY || to->type_kind == TYPE_STRUCT || to->type_kind == TYPE_UNION) { return insert_cast(expr, CAST_STST, to_type); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index b38f8a270..8168060c7 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -187,6 +187,7 @@ bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case CAST_PTRANY: case CAST_ENUMLOW: case CAST_VECARR: + case CAST_ARRVEC: if (eval_kind == CONSTANT_EVAL_FOLDABLE) return false; return expr_is_constant_eval(expr->cast_expr.expr, eval_kind); case CAST_EUINT: diff --git a/test/test_suite/vector/vector_to_array_cast.c3t b/test/test_suite/vector/vector_to_array_cast.c3t new file mode 100644 index 000000000..1ee0ff50f --- /dev/null +++ b/test/test_suite/vector/vector_to_array_cast.c3t @@ -0,0 +1,38 @@ +// #target: x64-darwin + +module test; + +int[<2>] b = (int[<2>])(int[2] { 1, 2 }); +int[2] c = (int[2])(int[<2>] { 1, 2 }); + +fn void tester() +{ + int[<2>] x = { 1, 2 }; + int[2] y = (int[2])(x); + x = (int[<2>])(y); +} + +/* #expect: test.ll + +@test.b = global <2 x i32> , align 8 +@test.c = global [2 x i32] [i32 1, i32 2], align 4 + +define void @test.tester() #0 { +entry: + %x = alloca <2 x i32>, align 8 + %y = alloca [2 x i32], align 4 + store <2 x i32> , <2 x i32>* %x, align 8 + %0 = load <2 x i32>, <2 x i32>* %x, align 8 + %1 = extractelement <2 x i32> %0, i64 0 + %2 = insertvalue [2 x i32] undef, i32 %1, 0 + %3 = extractelement <2 x i32> %0, i64 1 + %4 = insertvalue [2 x i32] %2, i32 %3, 1 + store [2 x i32] %4, [2 x i32]* %y, align 4 + %5 = load [2 x i32], [2 x i32]* %y, align 4 + %6 = extractvalue [2 x i32] %5, 0 + %7 = insertelement <2 x i32> undef, i32 %6, i64 0 + %8 = extractvalue [2 x i32] %5, 1 + %9 = insertelement <2 x i32> %7, i32 %8, i64 1 + store <2 x i32> %9, <2 x i32>* %x, align 8 + ret void +}