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 {
22392239 IrInstructionIdCheckRuntimeScope,
22402240 IrInstructionIdVectorToArray,
22412241 IrInstructionIdArrayToVector,
2242 IrInstructionIdAssertZero,
22422243};
22432244
22442245struct IrInstruction {
......@@ -3381,6 +3382,12 @@ struct IrInstructionVectorToArray {
33813382 LLVMValueRef tmp_ptr;
33823383};
33833384
3385struct IrInstructionAssertZero {
3386 IrInstruction base;
3387
3388 IrInstruction *target;
3389};
3390
33843391static const size_t slice_ptr_index = 0;
33853392static 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,
16511651 LLVMPositionBuilderAtEnd(g->builder, ok_block);
16521652}
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
16541668static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, ZigType *actual_type,
16551669 ZigType *wanted_type, LLVMValueRef expr_val)
16561670{
16571671 assert(actual_type->id == wanted_type->id);
1672 assert(expr_val != nullptr);
16581673
16591674 uint64_t actual_bits;
16601675 uint64_t wanted_bits;
......@@ -1707,17 +1722,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
17071722 if (!want_runtime_safety)
17081723 return nullptr;
17091724
1710 LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);
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;
1725 return gen_assert_zero(g, expr_val, actual_type);
17211726 }
17221727 LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
17231728 if (!want_runtime_safety) {
......@@ -5209,6 +5214,17 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab
52095214 return gen_load_untyped(g, casted_ptr, 0, false, "");
52105215}
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
52125228static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
52135229 AstNode *source_node = instruction->source_node;
52145230 Scope *scope = instruction->scope;
......@@ -5458,6 +5474,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
54585474 return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction);
54595475 case IrInstructionIdVectorToArray:
54605476 return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction);
5477 case IrInstructionIdAssertZero:
5478 return ir_render_assert_zero(g, executable, (IrInstructionAssertZero *)instruction);
54615479 }
54625480 zig_unreachable();
54635481}
src/ir.cpp+31
......@@ -908,6 +908,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayToVector *)
908908 return IrInstructionIdArrayToVector;
909909}
910910
911static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertZero *) {
912 return IrInstructionIdAssertZero;
913}
914
911915template<typename T>
912916static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
913917 T *special_instruction = allocate<T>(1);
......@@ -2858,6 +2862,19 @@ static IrInstruction *ir_build_array_to_vector(IrAnalyze *ira, IrInstruction *so
28582862 return &instruction->base;
28592863}
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
28612878static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
28622879 results[ReturnKindUnconditional] = 0;
28632880 results[ReturnKindError] = 0;
......@@ -10395,6 +10412,18 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction
1039510412 return result;
1039610413 }
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
1039810427 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
1039910428 source_instr->source_node, target);
1040010429 result->value.type = wanted_type;
......@@ -21705,6 +21734,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
2170521734 case IrInstructionIdCmpxchgGen:
2170621735 case IrInstructionIdArrayToVector:
2170721736 case IrInstructionIdVectorToArray:
21737 case IrInstructionIdAssertZero:
2170821738 zig_unreachable();
2170921739
2171021740 case IrInstructionIdReturn:
......@@ -22103,6 +22133,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2210322133 case IrInstructionIdAtomicRmw:
2210422134 case IrInstructionIdCmpxchgGen:
2210522135 case IrInstructionIdCmpxchgSrc:
22136 case IrInstructionIdAssertZero:
2210622137 return true;
2210722138
2210822139 case IrInstructionIdPhi:
src/ir_print.cpp+9
......@@ -984,6 +984,12 @@ static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *i
984984 fprintf(irp->f, ")");
985985}
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
987993static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) {
988994 fprintf(irp->f, "inttoerr ");
989995 ir_print_other_instruction(irp, instruction->target);
......@@ -1843,6 +1849,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
18431849 case IrInstructionIdVectorToArray:
18441850 ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction);
18451851 break;
1852 case IrInstructionIdAssertZero:
1853 ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction);
1854 break;
18461855 }
18471856 fprintf(irp->f, "\n");
18481857}
test/runtime_safety.zig+17
......@@ -362,6 +362,23 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
362362 \\}
363363 );
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
365382 // This case makes sure that the code compiles and runs. There is not actually a special
366383 // runtime safety check having to do specifically with error return traces across suspend points.
367384 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" {
471471 const x = @intToEnum(E, 0);
472472 assertOrPanic(x == E.A);
473473}
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" {
697697 assertOrPanic(y == 1);
698698}
699699
700test "@intCast to a u0" {
701 var x: u8 = 0;
702 var y: u0 = @intCast(u0, x);
703 assertOrPanic(y == 0);
704}
705
706700test "@bytesToslice on a packed struct" {
707701 const F = packed struct {
708702 a: u8,