authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-07 16:02:45-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-07 16:02:45-05:00
logf330eebe4bc6a036846cf05706f72855627c705a
tree7deea0f2c87091083fe5b59ab13d3924b645ea82
parent7843c96df87007561c107d11afa2fa74b46667fd

fix using the result of @intCast to u0

closes #1817

7 files changed, 104 insertions(+), 17 deletions(-)

src/all_types.hpp+7
...@@ -2239,6 +2239,7 @@ enum IrInstructionId {...@@ -2239,6 +2239,7 @@ enum IrInstructionId {
2239 IrInstructionIdCheckRuntimeScope,2239 IrInstructionIdCheckRuntimeScope,
2240 IrInstructionIdVectorToArray,2240 IrInstructionIdVectorToArray,
2241 IrInstructionIdArrayToVector,2241 IrInstructionIdArrayToVector,
2242 IrInstructionIdAssertZero,
2242};2243};
22432244
2244struct IrInstruction {2245struct IrInstruction {
...@@ -3381,6 +3382,12 @@ struct IrInstructionVectorToArray {...@@ -3381,6 +3382,12 @@ struct IrInstructionVectorToArray {
3381 LLVMValueRef tmp_ptr;3382 LLVMValueRef tmp_ptr;
3382};3383};
33833384
3385struct IrInstructionAssertZero {
3386 IrInstruction base;
3387
3388 IrInstruction *target;
3389};
3390
3384static const size_t slice_ptr_index = 0;3391static const size_t slice_ptr_index = 0;
3385static const size_t slice_len_index = 1;3392static const size_t slice_len_index = 1;
33863393
src/codegen.cpp+29-11
...@@ -1651,10 +1651,25 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,...@@ -1651,10 +1651,25 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
1651 LLVMPositionBuilderAtEnd(g->builder, ok_block);1651 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1652}1652}
16531653
1654static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType *int_type) {
1655 LLVMValueRef zero = LLVMConstNull(int_type->type_ref);
1656 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, "");
1657 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk");
1658 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail");
1659 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
1660
1661 LLVMPositionBuilderAtEnd(g->builder, fail_block);
1662 gen_safety_crash(g, PanicMsgIdCastTruncatedData);
1663
1664 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1665 return nullptr;
1666}
1667
1654static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, ZigType *actual_type,1668static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, ZigType *actual_type,
1655 ZigType *wanted_type, LLVMValueRef expr_val)1669 ZigType *wanted_type, LLVMValueRef expr_val)
1656{1670{
1657 assert(actual_type->id == wanted_type->id);1671 assert(actual_type->id == wanted_type->id);
1672 assert(expr_val != nullptr);
16581673
1659 uint64_t actual_bits;1674 uint64_t actual_bits;
1660 uint64_t wanted_bits;1675 uint64_t wanted_bits;
...@@ -1707,17 +1722,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z...@@ -1707,17 +1722,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
1707 if (!want_runtime_safety)1722 if (!want_runtime_safety)
1708 return nullptr;1723 return nullptr;
17091724
1710 LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);1725 return gen_assert_zero(g, expr_val, actual_type);
1711 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, "");
1712 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk");
1713 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail");
1714 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
1715
1716 LLVMPositionBuilderAtEnd(g->builder, fail_block);
1717 gen_safety_crash(g, PanicMsgIdCastTruncatedData);
1718
1719 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1720 return nullptr;
1721 }1726 }
1722 LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");1727 LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
1723 if (!want_runtime_safety) {1728 if (!want_runtime_safety) {
...@@ -5209,6 +5214,17 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab...@@ -5209,6 +5214,17 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab
5209 return gen_load_untyped(g, casted_ptr, 0, false, "");5214 return gen_load_untyped(g, casted_ptr, 0, false, "");
5210}5215}
52115216
5217static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable,
5218 IrInstructionAssertZero *instruction)
5219{
5220 LLVMValueRef target = ir_llvm_value(g, instruction->target);
5221 ZigType *int_type = instruction->target->value.type;
5222 if (ir_want_runtime_safety(g, &instruction->base)) {
5223 return gen_assert_zero(g, target, int_type);
5224 }
5225 return nullptr;
5226}
5227
5212static void set_debug_location(CodeGen *g, IrInstruction *instruction) {5228static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
5213 AstNode *source_node = instruction->source_node;5229 AstNode *source_node = instruction->source_node;
5214 Scope *scope = instruction->scope;5230 Scope *scope = instruction->scope;
...@@ -5458,6 +5474,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5458,6 +5474,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5458 return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction);5474 return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction);
5459 case IrInstructionIdVectorToArray:5475 case IrInstructionIdVectorToArray:
5460 return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction);5476 return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction);
5477 case IrInstructionIdAssertZero:
5478 return ir_render_assert_zero(g, executable, (IrInstructionAssertZero *)instruction);
5461 }5479 }
5462 zig_unreachable();5480 zig_unreachable();
5463}5481}
src/ir.cpp+31
...@@ -908,6 +908,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayToVector *)...@@ -908,6 +908,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayToVector *)
908 return IrInstructionIdArrayToVector;908 return IrInstructionIdArrayToVector;
909}909}
910910
911static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertZero *) {
912 return IrInstructionIdAssertZero;
913}
914
911template<typename T>915template<typename T>
912static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {916static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
913 T *special_instruction = allocate<T>(1);917 T *special_instruction = allocate<T>(1);
...@@ -2858,6 +2862,19 @@ static IrInstruction *ir_build_array_to_vector(IrAnalyze *ira, IrInstruction *so...@@ -2858,6 +2862,19 @@ static IrInstruction *ir_build_array_to_vector(IrAnalyze *ira, IrInstruction *so
2858 return &instruction->base;2862 return &instruction->base;
2859}2863}
28602864
2865static IrInstruction *ir_build_assert_zero(IrAnalyze *ira, IrInstruction *source_instruction,
2866 IrInstruction *target)
2867{
2868 IrInstructionAssertZero *instruction = ir_build_instruction<IrInstructionAssertZero>(&ira->new_irb,
2869 source_instruction->scope, source_instruction->source_node);
2870 instruction->base.value.type = ira->codegen->builtin_types.entry_void;
2871 instruction->target = target;
2872
2873 ir_ref_instruction(target, ira->new_irb.current_basic_block);
2874
2875 return &instruction->base;
2876}
2877
2861static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2878static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2862 results[ReturnKindUnconditional] = 0;2879 results[ReturnKindUnconditional] = 0;
2863 results[ReturnKindError] = 0;2880 results[ReturnKindError] = 0;
...@@ -10395,6 +10412,18 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction...@@ -10395,6 +10412,18 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction
10395 return result;10412 return result;
10396 }10413 }
1039710414
10415 // If the destination integer type has no bits, then we can emit a comptime
10416 // zero. However, we still want to emit a runtime safety check to make sure
10417 // the target is zero.
10418 if (!type_has_bits(wanted_type)) {
10419 assert(wanted_type->id == ZigTypeIdInt);
10420 assert(type_has_bits(target->value.type));
10421 ir_build_assert_zero(ira, source_instr, target);
10422 IrInstruction *result = ir_const_unsigned(ira, source_instr, 0);
10423 result->value.type = wanted_type;
10424 return result;
10425 }
10426
10398 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,10427 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
10399 source_instr->source_node, target);10428 source_instr->source_node, target);
10400 result->value.type = wanted_type;10429 result->value.type = wanted_type;
...@@ -21705,6 +21734,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio...@@ -21705,6 +21734,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
21705 case IrInstructionIdCmpxchgGen:21734 case IrInstructionIdCmpxchgGen:
21706 case IrInstructionIdArrayToVector:21735 case IrInstructionIdArrayToVector:
21707 case IrInstructionIdVectorToArray:21736 case IrInstructionIdVectorToArray:
21737 case IrInstructionIdAssertZero:
21708 zig_unreachable();21738 zig_unreachable();
2170921739
21710 case IrInstructionIdReturn:21740 case IrInstructionIdReturn:
...@@ -22103,6 +22133,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -22103,6 +22133,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
22103 case IrInstructionIdAtomicRmw:22133 case IrInstructionIdAtomicRmw:
22104 case IrInstructionIdCmpxchgGen:22134 case IrInstructionIdCmpxchgGen:
22105 case IrInstructionIdCmpxchgSrc:22135 case IrInstructionIdCmpxchgSrc:
22136 case IrInstructionIdAssertZero:
22106 return true;22137 return true;
2210722138
22108 case IrInstructionIdPhi:22139 case IrInstructionIdPhi:
src/ir_print.cpp+9
...@@ -984,6 +984,12 @@ static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *i...@@ -984,6 +984,12 @@ static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *i
984 fprintf(irp->f, ")");984 fprintf(irp->f, ")");
985}985}
986986
987static void ir_print_assert_zero(IrPrint *irp, IrInstructionAssertZero *instruction) {
988 fprintf(irp->f, "AssertZero(");
989 ir_print_other_instruction(irp, instruction->target);
990 fprintf(irp->f, ")");
991}
992
987static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) {993static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) {
988 fprintf(irp->f, "inttoerr ");994 fprintf(irp->f, "inttoerr ");
989 ir_print_other_instruction(irp, instruction->target);995 ir_print_other_instruction(irp, instruction->target);
...@@ -1843,6 +1849,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1843,6 +1849,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1843 case IrInstructionIdVectorToArray:1849 case IrInstructionIdVectorToArray:
1844 ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction);1850 ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction);
1845 break;1851 break;
1852 case IrInstructionIdAssertZero:
1853 ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction);
1854 break;
1846 }1855 }
1847 fprintf(irp->f, "\n");1856 fprintf(irp->f, "\n");
1848}1857}
test/runtime_safety.zig+17
...@@ -362,6 +362,23 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -362,6 +362,23 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
362 \\}362 \\}
363 );363 );
364364
365 // @intCast a runtime integer to u0 actually results in a comptime-known value,
366 // but we still emit a safety check to ensure the integer was 0 and thus
367 // did not truncate information.
368 cases.addRuntimeSafety("@intCast to u0",
369 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
370 \\ @import("std").os.exit(126);
371 \\}
372 \\
373 \\pub fn main() void {
374 \\ bar(1, 1);
375 \\}
376 \\
377 \\fn bar(one: u1, not_zero: i32) void {
378 \\ var x = one << @intCast(u0, not_zero);
379 \\}
380 );
381
365 // This case makes sure that the code compiles and runs. There is not actually a special382 // This case makes sure that the code compiles and runs. There is not actually a special
366 // runtime safety check having to do specifically with error return traces across suspend points.383 // runtime safety check having to do specifically with error return traces across suspend points.
367 cases.addRuntimeSafety("error return trace across suspend points",384 cases.addRuntimeSafety("error return trace across suspend points",
test/stage1/behavior/cast.zig+11
...@@ -471,3 +471,14 @@ test "@intToEnum passed a comptime_int to an enum with one item" {...@@ -471,3 +471,14 @@ test "@intToEnum passed a comptime_int to an enum with one item" {
471 const x = @intToEnum(E, 0);471 const x = @intToEnum(E, 0);
472 assertOrPanic(x == E.A);472 assertOrPanic(x == E.A);
473}473}
474
475test "@intCast to u0 and use the result" {
476 const S = struct {
477 fn doTheTest(zero: u1, one: u1, bigzero: i32) void {
478 assertOrPanic((one << @intCast(u0, bigzero)) == 1);
479 assertOrPanic((zero << @intCast(u0, bigzero)) == 0);
480 }
481 };
482 S.doTheTest(0, 1, 0);
483 comptime S.doTheTest(0, 1, 0);
484}
test/stage1/behavior/eval.zig-6
...@@ -697,12 +697,6 @@ test "bit shift a u1" {...@@ -697,12 +697,6 @@ test "bit shift a u1" {
697 assertOrPanic(y == 1);697 assertOrPanic(y == 1);
698}698}
699699
700test "@intCast to a u0" {
701 var x: u8 = 0;
702 var y: u0 = @intCast(u0, x);
703 assertOrPanic(y == 0);
704}
705
706test "@bytesToslice on a packed struct" {700test "@bytesToslice on a packed struct" {
707 const F = packed struct {701 const F = packed struct {
708 a: u8,702 a: u8,