authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-01-13 22:18:49+01:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-01-13 22:18:49+01:00
logcae93c860bc2c599618482a4190daf619a0c69e2
treec61934554aeab9798a0bc8ae29ab95c80b54eefe
parent84930fec279a8bf0e7ce79c79a7ccd98d1ef4d0d

Allow switching on pointer types

Closes #4074

2 files changed, 46 insertions(+), 3 deletions(-)

src/codegen.cpp+19-3
......@@ -4876,14 +4876,30 @@ static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, Ir
48764876}
48774877
48784878static 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;
48804880 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
48814888 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_value, else_block,
4882 (unsigned)instruction->case_count);
4889 (unsigned)instruction->case_count);
4890
48834891 for (size_t i = 0; i < instruction->case_count; i += 1) {
48844892 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);
48864901 }
4902
48874903 return nullptr;
48884904}
48894905
test/stage1/behavior/switch.zig+27
......@@ -452,3 +452,30 @@ test "switch on global mutable var isn't constant-folded" {
452452 poll();
453453 }
454454}
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}