authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-10-17 09:46:11+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-10-19 20:05:09+02:00
log2f465761bb960ef945f62186ba0b38a95684af51
treed0bd076ba334b0b93d17c4e031dd95575894c942
parent245d98d32dd29e80de9732f415a4731748008acf

stage1: Implement `@intCast` between vectors

Explicit and implicit integer casts on vector types are now supported and follow the same rules as their scalar counterparts. Implicit float casts are accidentally supported, `@floatCast` is still not vector-aware.

5 files changed, 228 insertions(+), 39 deletions(-)

src/stage1/codegen.cpp+29-15
......@@ -1433,6 +1433,9 @@ static void add_sentinel_check(CodeGen *g, LLVMValueRef sentinel_elem_ptr, ZigVa
14331433static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType *int_type) {
14341434 LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, int_type));
14351435 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, "");
1436 if (int_type->id == ZigTypeIdVector) {
1437 ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit);
1438 }
14361439 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk");
14371440 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail");
14381441 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
......@@ -1450,29 +1453,37 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
14501453 assert(actual_type->id == wanted_type->id);
14511454 assert(expr_val != nullptr);
14521455
1456 ZigType *scalar_actual_type = (actual_type->id == ZigTypeIdVector) ?
1457 actual_type->data.vector.elem_type : actual_type;
1458 ZigType *scalar_wanted_type = (wanted_type->id == ZigTypeIdVector) ?
1459 wanted_type->data.vector.elem_type : wanted_type;
1460
14531461 uint64_t actual_bits;
14541462 uint64_t wanted_bits;
1455 if (actual_type->id == ZigTypeIdFloat) {
1456 actual_bits = actual_type->data.floating.bit_count;
1457 wanted_bits = wanted_type->data.floating.bit_count;
1458 } else if (actual_type->id == ZigTypeIdInt) {
1459 actual_bits = actual_type->data.integral.bit_count;
1460 wanted_bits = wanted_type->data.integral.bit_count;
1463 if (scalar_actual_type->id == ZigTypeIdFloat) {
1464 actual_bits = scalar_actual_type->data.floating.bit_count;
1465 wanted_bits = scalar_wanted_type->data.floating.bit_count;
1466 } else if (scalar_actual_type->id == ZigTypeIdInt) {
1467 actual_bits = scalar_actual_type->data.integral.bit_count;
1468 wanted_bits = scalar_wanted_type->data.integral.bit_count;
14611469 } else {
14621470 zig_unreachable();
14631471 }
14641472
1465 if (actual_type->id == ZigTypeIdInt && want_runtime_safety && (
1473 if (scalar_actual_type->id == ZigTypeIdInt && want_runtime_safety && (
14661474 // negative to unsigned
1467 (!wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed) ||
1475 (!scalar_wanted_type->data.integral.is_signed && scalar_actual_type->data.integral.is_signed) ||
14681476 // unsigned would become negative
1469 (wanted_type->data.integral.is_signed && !actual_type->data.integral.is_signed && actual_bits == wanted_bits)))
1477 (scalar_wanted_type->data.integral.is_signed && !scalar_actual_type->data.integral.is_signed && actual_bits == wanted_bits)))
14701478 {
14711479 LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, actual_type));
14721480 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, "");
14731481
14741482 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastOk");
14751483 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastFail");
1484 if (actual_type->id == ZigTypeIdVector) {
1485 ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit);
1486 }
14761487 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
14771488
14781489 LLVMPositionBuilderAtEnd(g->builder, fail_block);
......@@ -1484,10 +1495,10 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
14841495 if (actual_bits == wanted_bits) {
14851496 return expr_val;
14861497 } else if (actual_bits < wanted_bits) {
1487 if (actual_type->id == ZigTypeIdFloat) {
1498 if (scalar_actual_type->id == ZigTypeIdFloat) {
14881499 return LLVMBuildFPExt(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
1489 } else if (actual_type->id == ZigTypeIdInt) {
1490 if (actual_type->data.integral.is_signed) {
1500 } else if (scalar_actual_type->id == ZigTypeIdInt) {
1501 if (scalar_actual_type->data.integral.is_signed) {
14911502 return LLVMBuildSExt(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
14921503 } else {
14931504 return LLVMBuildZExt(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
......@@ -1496,9 +1507,9 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
14961507 zig_unreachable();
14971508 }
14981509 } else if (actual_bits > wanted_bits) {
1499 if (actual_type->id == ZigTypeIdFloat) {
1510 if (scalar_actual_type->id == ZigTypeIdFloat) {
15001511 return LLVMBuildFPTrunc(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
1501 } else if (actual_type->id == ZigTypeIdInt) {
1512 } else if (scalar_actual_type->id == ZigTypeIdInt) {
15021513 if (wanted_bits == 0) {
15031514 if (!want_runtime_safety)
15041515 return nullptr;
......@@ -1510,12 +1521,15 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
15101521 return trunc_val;
15111522 }
15121523 LLVMValueRef orig_val;
1513 if (wanted_type->data.integral.is_signed) {
1524 if (scalar_wanted_type->data.integral.is_signed) {
15141525 orig_val = LLVMBuildSExt(g->builder, trunc_val, get_llvm_type(g, actual_type), "");
15151526 } else {
15161527 orig_val = LLVMBuildZExt(g->builder, trunc_val, get_llvm_type(g, actual_type), "");
15171528 }
15181529 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, orig_val, "");
1530 if (actual_type->id == ZigTypeIdVector) {
1531 ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit);
1532 }
15191533 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk");
15201534 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail");
15211535 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
src/stage1/ir.cpp+129-21
......@@ -86,6 +86,8 @@ enum ConstCastResultId {
8686 ConstCastResultIdCV,
8787 ConstCastResultIdPtrSentinel,
8888 ConstCastResultIdIntShorten,
89 ConstCastResultIdVectorLength,
90 ConstCastResultIdVectorChild,
8991};
9092
9193struct ConstCastOnly;
......@@ -914,6 +916,7 @@ static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expecte
914916 if (is_opt_err_set(expected) && is_opt_err_set(actual))
915917 return true;
916918
919 // XXX: Vectors and arrays are interchangeable at comptime
917920 if (expected->id != actual->id)
918921 return false;
919922
......@@ -947,9 +950,11 @@ static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expecte
947950 case ZigTypeIdErrorUnion:
948951 case ZigTypeIdEnum:
949952 case ZigTypeIdUnion:
950 case ZigTypeIdVector:
951953 case ZigTypeIdFnFrame:
952954 return false;
955 case ZigTypeIdVector:
956 return expected->data.vector.len == actual->data.vector.len &&
957 types_have_same_zig_comptime_repr(codegen, expected->data.vector.elem_type, actual->data.vector.elem_type);
953958 case ZigTypeIdArray:
954959 return expected->data.array.len == actual->data.array.len &&
955960 expected->data.array.child_type == actual->data.array.child_type &&
......@@ -12190,6 +12195,24 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
1219012195 return result;
1219112196 }
1219212197
12198 if (wanted_type->id == ZigTypeIdVector && actual_type->id == ZigTypeIdVector) {
12199 if (actual_type->data.vector.len != wanted_type->data.vector.len) {
12200 result.id = ConstCastResultIdVectorLength;
12201 return result;
12202 }
12203
12204 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.vector.elem_type,
12205 actual_type->data.vector.elem_type, source_node, false);
12206 if (child.id == ConstCastResultIdInvalid)
12207 return child;
12208 if (child.id != ConstCastResultIdOk) {
12209 result.id = ConstCastResultIdVectorChild;
12210 return result;
12211 }
12212
12213 return result;
12214 }
12215
1219312216 result.id = ConstCastResultIdType;
1219412217 result.data.type_mismatch = heap::c_allocator.allocate_nonzero<ConstCastTypeMismatch>(1);
1219512218 result.data.type_mismatch->wanted_type = wanted_type;
......@@ -14306,37 +14329,62 @@ static IrInstGen *ir_analyze_enum_to_union(IrAnalyze *ira, IrInst* source_instr,
1430614329 return ira->codegen->invalid_inst_gen;
1430714330}
1430814331
14332static bool value_numeric_fits_in_type(ZigValue *value, ZigType *type_entry);
14333
1430914334static IrInstGen *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInst* source_instr,
1431014335 IrInstGen *target, ZigType *wanted_type)
1431114336{
14312 assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdFloat);
14337 ZigType *wanted_scalar_type = (target->value->type->id == ZigTypeIdVector) ?
14338 wanted_type->data.vector.elem_type : wanted_type;
14339
14340 assert(wanted_scalar_type->id == ZigTypeIdInt || wanted_scalar_type->id == ZigTypeIdFloat);
1431314341
1431414342 if (instr_is_comptime(target)) {
1431514343 ZigValue *val = ir_resolve_const(ira, target, UndefBad);
1431614344 if (!val)
1431714345 return ira->codegen->invalid_inst_gen;
14318 if (wanted_type->id == ZigTypeIdInt) {
14319 if (bigint_cmp_zero(&val->data.x_bigint) == CmpLT && !wanted_type->data.integral.is_signed) {
14346
14347 if (wanted_scalar_type->id == ZigTypeIdInt) {
14348 if (!wanted_scalar_type->data.integral.is_signed && value_cmp_numeric_val_any(val, CmpLT, nullptr)) {
1432014349 ir_add_error(ira, source_instr,
1432114350 buf_sprintf("attempt to cast negative value to unsigned integer"));
1432214351 return ira->codegen->invalid_inst_gen;
1432314352 }
14324 if (!bigint_fits_in_bits(&val->data.x_bigint, wanted_type->data.integral.bit_count,
14325 wanted_type->data.integral.is_signed))
14326 {
14353 if (!value_numeric_fits_in_type(val, wanted_scalar_type)) {
1432714354 ir_add_error(ira, source_instr,
1432814355 buf_sprintf("cast from '%s' to '%s' truncates bits",
14329 buf_ptr(&target->value->type->name), buf_ptr(&wanted_type->name)));
14356 buf_ptr(&target->value->type->name), buf_ptr(&wanted_scalar_type->name)));
1433014357 return ira->codegen->invalid_inst_gen;
1433114358 }
1433214359 }
14360
1433314361 IrInstGen *result = ir_const(ira, source_instr, wanted_type);
1433414362 result->value->type = wanted_type;
14335 if (wanted_type->id == ZigTypeIdInt) {
14336 bigint_init_bigint(&result->value->data.x_bigint, &val->data.x_bigint);
14363
14364 if (wanted_type->id == ZigTypeIdVector) {
14365 result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate<ZigValue>(wanted_type->data.vector.len);
14366
14367 for (size_t i = 0; i < wanted_type->data.vector.len; i++) {
14368 ZigValue *scalar_dest_value = &result->value->data.x_array.data.s_none.elements[i];
14369 ZigValue *scalar_src_value = &val->data.x_array.data.s_none.elements[i];
14370
14371 scalar_dest_value->type = wanted_scalar_type;
14372 scalar_dest_value->special = ConstValSpecialStatic;
14373
14374 if (wanted_scalar_type->id == ZigTypeIdInt) {
14375 bigint_init_bigint(&scalar_dest_value->data.x_bigint, &scalar_src_value->data.x_bigint);
14376 } else {
14377 float_init_float(scalar_dest_value, scalar_src_value);
14378 }
14379 }
1433714380 } else {
14338 float_init_float(result->value, val);
14381 if (wanted_type->id == ZigTypeIdInt) {
14382 bigint_init_bigint(&result->value->data.x_bigint, &val->data.x_bigint);
14383 } else {
14384 float_init_float(result->value, val);
14385 }
1433914386 }
14387
1434014388 return result;
1434114389 }
1434214390
......@@ -14779,6 +14827,8 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
1477914827 actual_signed, actual_type->data.integral.bit_count));
1478014828 break;
1478114829 }
14830 case ConstCastResultIdVectorLength: // TODO
14831 case ConstCastResultIdVectorChild: // TODO
1478214832 case ConstCastResultIdFnAlign: // TODO
1478314833 case ConstCastResultIdFnVarArgs: // TODO
1478414834 case ConstCastResultIdFnReturnType: // TODO
......@@ -15462,12 +15512,35 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr,
1546215512 }
1546315513
1546415514 // @Vector(N,T1) to @Vector(N,T2)
15465 if (actual_type->id == ZigTypeIdVector && wanted_type->id == ZigTypeIdVector) {
15466 if (actual_type->data.vector.len == wanted_type->data.vector.len &&
15467 types_match_const_cast_only(ira, wanted_type->data.vector.elem_type,
15468 actual_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk)
15515 if (actual_type->id == ZigTypeIdVector && wanted_type->id == ZigTypeIdVector &&
15516 actual_type->data.vector.len == wanted_type->data.vector.len)
15517 {
15518 ZigType *scalar_actual_type = actual_type->data.vector.elem_type;
15519 ZigType *scalar_wanted_type = wanted_type->data.vector.elem_type;
15520
15521 // widening conversion
15522 if (scalar_wanted_type->id == ZigTypeIdInt &&
15523 scalar_actual_type->id == ZigTypeIdInt &&
15524 scalar_wanted_type->data.integral.is_signed == scalar_actual_type->data.integral.is_signed &&
15525 scalar_wanted_type->data.integral.bit_count >= scalar_actual_type->data.integral.bit_count)
15526 {
15527 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
15528 }
15529
15530 // small enough unsigned ints can get casted to large enough signed ints
15531 if (scalar_wanted_type->id == ZigTypeIdInt && scalar_wanted_type->data.integral.is_signed &&
15532 scalar_actual_type->id == ZigTypeIdInt && !scalar_actual_type->data.integral.is_signed &&
15533 scalar_wanted_type->data.integral.bit_count > scalar_actual_type->data.integral.bit_count)
15534 {
15535 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
15536 }
15537
15538 // float widening conversion
15539 if (scalar_wanted_type->id == ZigTypeIdFloat &&
15540 scalar_actual_type->id == ZigTypeIdFloat &&
15541 scalar_wanted_type->data.floating.bit_count >= scalar_actual_type->data.floating.bit_count)
1546915542 {
15470 return ir_analyze_bit_cast(ira, source_instr, value, wanted_type);
15543 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
1547115544 }
1547215545 }
1547315546
......@@ -17728,6 +17801,33 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
1772817801 zig_unreachable();
1772917802}
1773017803
17804// Returns true if integer `value` can be converted to `type_entry` without
17805// losing data.
17806// If `value` is a vector the function returns true if this is valid for every
17807// element.
17808static bool value_numeric_fits_in_type(ZigValue *value, ZigType *type_entry) {
17809 assert(value->special == ConstValSpecialStatic);
17810 assert(type_entry->id == ZigTypeIdInt);
17811
17812 switch (value->type->id) {
17813 case ZigTypeIdComptimeInt:
17814 case ZigTypeIdInt: {
17815 return bigint_fits_in_bits(&value->data.x_bigint, type_entry->data.integral.bit_count,
17816 type_entry->data.integral.is_signed);
17817 }
17818 case ZigTypeIdVector: {
17819 for (size_t i = 0; i < value->type->data.vector.len; i++) {
17820 ZigValue *scalar_value = &value->data.x_array.data.s_none.elements[i];
17821 const bool result = bigint_fits_in_bits(&scalar_value->data.x_bigint,
17822 type_entry->data.integral.bit_count, type_entry->data.integral.is_signed);
17823 if (!result) return false;
17824 }
17825 return true;
17826 }
17827 default: zig_unreachable();
17828 }
17829}
17830
1773117831static bool value_cmp_numeric_val(ZigValue *left, Cmp predicate, ZigValue *right, bool any) {
1773217832 assert(left->special == ConstValSpecialStatic);
1773317833 assert(right == nullptr || right->special == ConstValSpecialStatic);
......@@ -27154,8 +27254,12 @@ static IrInstGen *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstSrcIntCa
2715427254 if (type_is_invalid(dest_type))
2715527255 return ira->codegen->invalid_inst_gen;
2715627256
27157 if (dest_type->id != ZigTypeIdInt && dest_type->id != ZigTypeIdComptimeInt) {
27158 ir_add_error(ira, &instruction->dest_type->base, buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name)));
27257 ZigType *scalar_dest_type = (dest_type->id == ZigTypeIdVector) ?
27258 dest_type->data.vector.elem_type : dest_type;
27259
27260 if (scalar_dest_type->id != ZigTypeIdInt && scalar_dest_type->id != ZigTypeIdComptimeInt) {
27261 ir_add_error(ira, &instruction->dest_type->base,
27262 buf_sprintf("expected integer type, found '%s'", buf_ptr(&scalar_dest_type->name)));
2715927263 return ira->codegen->invalid_inst_gen;
2716027264 }
2716127265
......@@ -27163,13 +27267,16 @@ static IrInstGen *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstSrcIntCa
2716327267 if (type_is_invalid(target->value->type))
2716427268 return ira->codegen->invalid_inst_gen;
2716527269
27166 if (target->value->type->id != ZigTypeIdInt && target->value->type->id != ZigTypeIdComptimeInt) {
27270 ZigType *scalar_target_type = (target->value->type->id == ZigTypeIdVector) ?
27271 target->value->type->data.vector.elem_type : target->value->type;
27272
27273 if (scalar_target_type->id != ZigTypeIdInt && scalar_target_type->id != ZigTypeIdComptimeInt) {
2716727274 ir_add_error(ira, &instruction->target->base, buf_sprintf("expected integer type, found '%s'",
27168 buf_ptr(&target->value->type->name)));
27275 buf_ptr(&scalar_target_type->name)));
2716927276 return ira->codegen->invalid_inst_gen;
2717027277 }
2717127278
27172 if (instr_is_comptime(target) || dest_type->id == ZigTypeIdComptimeInt) {
27279 if (scalar_dest_type->id == ZigTypeIdComptimeInt) {
2717327280 ZigValue *val = ir_resolve_const(ira, target, UndefBad);
2717427281 if (val == nullptr)
2717527282 return ira->codegen->invalid_inst_gen;
......@@ -27222,6 +27329,7 @@ static IrInstGen *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstSrcFlo
2722227329 if (val == nullptr)
2722327330 return ira->codegen->invalid_inst_gen;
2722427331
27332 // XXX: This will trigger an assertion failure if dest_type is comptime_float
2722527333 return ir_analyze_widen_or_shorten(ira, &instruction->target->base, target, dest_type);
2722627334 }
2722727335
test/compile_errors.zig+2-3
......@@ -2944,7 +2944,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29442944 "tmp.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void",
29452945 "tmp.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'",
29462946 });
2947
29482947 cases.add("cast negative value to unsigned integer",
29492948 \\comptime {
29502949 \\ const value: i32 = -1;
......@@ -2955,7 +2954,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29552954 \\ const unsigned: u32 = value;
29562955 \\}
29572956 , &[_][]const u8{
2958 "tmp.zig:3:36: error: cannot cast negative value -1 to unsigned integer type 'u32'",
2957 "tmp.zig:3:22: error: attempt to cast negative value to unsigned integer",
29592958 "tmp.zig:7:27: error: cannot cast negative value -1 to unsigned integer type 'u32'",
29602959 });
29612960
......@@ -2977,7 +2976,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
29772976 \\ var unsigned: u64 = signed;
29782977 \\}
29792978 , &[_][]const u8{
2980 "tmp.zig:3:31: error: integer value 300 cannot be coerced to type 'u8'",
2979 "tmp.zig:3:18: error: cast from 'u16' to 'u8' truncates bits",
29812980 "tmp.zig:7:22: error: integer value 300 cannot be coerced to type 'u8'",
29822981 "tmp.zig:11:20: error: expected type 'u8', found 'u16'",
29832982 "tmp.zig:11:20: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values",
test/runtime_safety.zig+30
......@@ -70,6 +70,36 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
7070 );
7171 }
7272
73 cases.addRuntimeSafety("truncating vector cast",
74 \\const std = @import("std");
75 \\const V = @import("std").meta.Vector;
76 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
77 \\ if (std.mem.eql(u8, message, "integer cast truncated bits")) {
78 \\ std.process.exit(126); // good
79 \\ }
80 \\ std.process.exit(0); // test failed
81 \\}
82 \\pub fn main() void {
83 \\ var x = @splat(4, @as(u32, 0xdeadbeef));
84 \\ var y = @intCast(V(4, u16), x);
85 \\}
86 );
87
88 cases.addRuntimeSafety("unsigned-signed vector cast",
89 \\const std = @import("std");
90 \\const V = @import("std").meta.Vector;
91 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
92 \\ if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) {
93 \\ std.process.exit(126); // good
94 \\ }
95 \\ std.process.exit(0); // test failed
96 \\}
97 \\pub fn main() void {
98 \\ var x = @splat(4, @as(u32, 0x80000000));
99 \\ var y = @intCast(V(4, i32), x);
100 \\}
101 );
102
73103 cases.addRuntimeSafety("shift left by huge amount",
74104 \\const std = @import("std");
75105 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
test/stage1/behavior/cast.zig+38
......@@ -2,6 +2,7 @@ const std = @import("std");
22const expect = std.testing.expect;
33const mem = std.mem;
44const maxInt = std.math.maxInt;
5const Vector = std.meta.Vector;
56
67test "int to ptr cast" {
78 const x = @as(usize, 13);
......@@ -364,6 +365,43 @@ test "@floatCast comptime_int and comptime_float" {
364365 }
365366}
366367
368test "vector casts" {
369 const S = struct {
370 fn doTheTest() void {
371 // Upcast (implicit, equivalent to @intCast)
372 var up0: Vector(2, u8) = [_]u8{ 0x55, 0xaa };
373 var up1 = @as(Vector(2, u16), up0);
374 var up2 = @as(Vector(2, u32), up0);
375 var up3 = @as(Vector(2, u64), up0);
376 // Downcast (safety-checked)
377 var down0 = up3;
378 var down1 = @intCast(Vector(2, u32), down0);
379 var down2 = @intCast(Vector(2, u16), down0);
380 var down3 = @intCast(Vector(2, u8), down0);
381
382 expect(mem.eql(u16, &@as([2]u16, up1), &[2]u16{ 0x55, 0xaa }));
383 expect(mem.eql(u32, &@as([2]u32, up2), &[2]u32{ 0x55, 0xaa }));
384 expect(mem.eql(u64, &@as([2]u64, up3), &[2]u64{ 0x55, 0xaa }));
385
386 expect(mem.eql(u32, &@as([2]u32, down1), &[2]u32{ 0x55, 0xaa }));
387 expect(mem.eql(u16, &@as([2]u16, down2), &[2]u16{ 0x55, 0xaa }));
388 expect(mem.eql(u8, &@as([2]u8, down3), &[2]u8{ 0x55, 0xaa }));
389 }
390
391 fn doTheTestFloat() void {
392 var vec = @splat(2, @as(f32, 1234.0));
393 var wider: Vector(2, f64) = vec;
394 expect(wider[0] == 1234.0);
395 expect(wider[1] == 1234.0);
396 }
397 };
398
399 S.doTheTest();
400 comptime S.doTheTest();
401 S.doTheTestFloat();
402 comptime S.doTheTestFloat();
403}
404
367405test "comptime_int @intToFloat" {
368406 {
369407 const result = @intToFloat(f16, 1234);