authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-13 18:01:19-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-01-13 18:01:19-05:00
logd3e67d99216d3dd6c18259c17652fcad54aebc21
treec61934554aeab9798a0bc8ae29ab95c80b54eefe
parentb9f37ffe19e30da1fd79cd01dbb6191ec2733b5c
parentcae93c860bc2c599618482a4190daf619a0c69e2
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4172 from LemonBoy/swish

Two switch-related patches

4 files changed, 72 insertions(+), 3 deletions(-)

src/codegen.cpp+19-3
...@@ -4876,14 +4876,30 @@ static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, Ir...@@ -4876,14 +4876,30 @@ static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, Ir
4876}4876}
48774877
4878static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) {4878static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) {
4879 LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value);4879 ZigType *target_type = instruction->target_value->value->type;
4880 LLVMBasicBlockRef else_block = instruction->else_block->llvm_block;4880 LLVMBasicBlockRef else_block = instruction->else_block->llvm_block;
4881
4882 LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value);
4883 if (target_type->id == ZigTypeIdPointer) {
4884 const ZigType *usize = g->builtin_types.entry_usize;
4885 target_value = LLVMBuildPtrToInt(g->builder, target_value, usize->llvm_type, "");
4886 }
4887
4881 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_value, else_block,4888 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_value, else_block,
4882 (unsigned)instruction->case_count);4889 (unsigned)instruction->case_count);
4890
4883 for (size_t i = 0; i < instruction->case_count; i += 1) {4891 for (size_t i = 0; i < instruction->case_count; i += 1) {
4884 IrInstructionSwitchBrCase *this_case = &instruction->cases[i];4892 IrInstructionSwitchBrCase *this_case = &instruction->cases[i];
4885 LLVMAddCase(switch_instr, ir_llvm_value(g, this_case->value), this_case->block->llvm_block);4893
4894 LLVMValueRef case_value = ir_llvm_value(g, this_case->value);
4895 if (target_type->id == ZigTypeIdPointer) {
4896 const ZigType *usize = g->builtin_types.entry_usize;
4897 case_value = LLVMBuildPtrToInt(g->builder, case_value, usize->llvm_type, "");
4898 }
4899
4900 LLVMAddCase(switch_instr, case_value, this_case->block->llvm_block);
4886 }4901 }
4902
4887 return nullptr;4903 return nullptr;
4888}4904}
48894905
src/ir.cpp+12
...@@ -26394,6 +26394,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,...@@ -26394,6 +26394,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
26394 if (type_is_invalid(end_value->value->type))26394 if (type_is_invalid(end_value->value->type))
26395 return ira->codegen->invalid_instruction;26395 return ira->codegen->invalid_instruction;
2639626396
26397 assert(start_value->value->type->id == ZigTypeIdEnum);
26397 BigInt start_index;26398 BigInt start_index;
26398 bigint_init_bigint(&start_index, &start_value->value->data.x_enum_tag);26399 bigint_init_bigint(&start_index, &start_value->value->data.x_enum_tag);
2639926400
...@@ -26401,6 +26402,11 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,...@@ -26401,6 +26402,11 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
26401 BigInt end_index;26402 BigInt end_index;
26402 bigint_init_bigint(&end_index, &end_value->value->data.x_enum_tag);26403 bigint_init_bigint(&end_index, &end_value->value->data.x_enum_tag);
2640326404
26405 if (bigint_cmp(&start_index, &end_index) == CmpGT) {
26406 ir_add_error(ira, start_value,
26407 buf_sprintf("range start value is greater than the end value"));
26408 }
26409
26404 BigInt field_index;26410 BigInt field_index;
26405 bigint_init_bigint(&field_index, &start_index);26411 bigint_init_bigint(&field_index, &start_index);
26406 for (;;) {26412 for (;;) {
...@@ -26530,6 +26536,12 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,...@@ -26530,6 +26536,12 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
2653026536
26531 assert(start_val->type->id == ZigTypeIdInt || start_val->type->id == ZigTypeIdComptimeInt);26537 assert(start_val->type->id == ZigTypeIdInt || start_val->type->id == ZigTypeIdComptimeInt);
26532 assert(end_val->type->id == ZigTypeIdInt || end_val->type->id == ZigTypeIdComptimeInt);26538 assert(end_val->type->id == ZigTypeIdInt || end_val->type->id == ZigTypeIdComptimeInt);
26539
26540 if (bigint_cmp(&start_val->data.x_bigint, &end_val->data.x_bigint) == CmpGT) {
26541 ir_add_error(ira, start_value,
26542 buf_sprintf("range start value is greater than the end value"));
26543 }
26544
26533 AstNode *prev_node = rangeset_add_range(&rs, &start_val->data.x_bigint, &end_val->data.x_bigint,26545 AstNode *prev_node = rangeset_add_range(&rs, &start_val->data.x_bigint, &end_val->data.x_bigint,
26534 start_value->source_node);26546 start_value->source_node);
26535 if (prev_node != nullptr) {26547 if (prev_node != nullptr) {
test/compile_errors.zig+14
...@@ -2,6 +2,20 @@ const tests = @import("tests.zig");...@@ -2,6 +2,20 @@ const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.addTest("switch ranges endpoints are validated",
6 \\pub export fn entry() void {
7 \\ var x: i32 = 0;
8 \\ switch (x) {
9 \\ 6...1 => {},
10 \\ -1...-5 => {},
11 \\ else => unreachable,
12 \\ }
13 \\}
14 , &[_][]const u8{
15 "tmp.zig:4:9: error: range start value is greater than the end value",
16 "tmp.zig:5:9: error: range start value is greater than the end value",
17 });
18
5 cases.addTest("errors in for loop bodies are propagated",19 cases.addTest("errors in for loop bodies are propagated",
6 \\pub export fn entry() void {20 \\pub export fn entry() void {
7 \\ var arr: [100]u8 = undefined;21 \\ var arr: [100]u8 = undefined;
test/stage1/behavior/switch.zig+27
...@@ -452,3 +452,30 @@ test "switch on global mutable var isn't constant-folded" {...@@ -452,3 +452,30 @@ test "switch on global mutable var isn't constant-folded" {
452 poll();452 poll();
453 }453 }
454}454}
455
456test "switch on pointer type" {
457 const S = struct {
458 const X = struct {
459 field: u32,
460 };
461
462 const P1 = @intToPtr(*X, 0x400);
463 const P2 = @intToPtr(*X, 0x800);
464 const P3 = @intToPtr(*X, 0xC00);
465
466 fn doTheTest(arg: *X) i32 {
467 switch (arg) {
468 P1 => return 1,
469 P2 => return 2,
470 else => return 3,
471 }
472 }
473 };
474
475 expect(1 == S.doTheTest(S.P1));
476 expect(2 == S.doTheTest(S.P2));
477 expect(3 == S.doTheTest(S.P3));
478 comptime expect(1 == S.doTheTest(S.P1));
479 comptime expect(2 == S.doTheTest(S.P2));
480 comptime expect(3 == S.doTheTest(S.P3));
481}