From c64f9991d561ff9a8e3c4575e8149404784497d3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 17 Dec 2016 17:48:07 -0500 Subject: [PATCH] IR: fix switching on enum --- src/codegen.cpp | 33 +++++++++++++++++++++++------ src/ir.cpp | 53 ++++++++++++++++++++++++++++++++++++++++------- std/bootstrap.zig | 8 +++---- std/io.zig | 42 ++++++++++++++++++------------------- 4 files changed, 98 insertions(+), 38 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 2f540b63aa..88b565866a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1420,12 +1420,12 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable, IrInstructionEnumFieldPtr *instruction) { - LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr); TypeEnumField *field = instruction->field; if (!type_has_bits(field->type_entry)) return nullptr; + LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr); LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0); LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_gen_union_index, ""); LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); @@ -2140,6 +2140,20 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa return instruction->tmp_ptr; } +static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrInstructionEnumTag *instruction) { + TypeTableEntry *enum_type = instruction->value->type_entry; + TypeTableEntry *tag_type = enum_type->data.enumeration.tag_type; + if (!type_has_bits(tag_type)) + return nullptr; + + LLVMValueRef enum_val = ir_llvm_value(g, instruction->value); + if (enum_type->data.enumeration.gen_field_count == 0) + return enum_val; + + LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_gen_tag_index, ""); + return get_handle_value(g, tag_field_ptr, tag_type); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -2271,10 +2285,11 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction); case IrInstructionIdErrWrapPayload: return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction); + case IrInstructionIdEnumTag: + return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction); case IrInstructionIdSwitchVar: case IrInstructionIdContainerInitList: case IrInstructionIdStructInit: - case IrInstructionIdEnumTag: zig_panic("TODO render more IR instructions to LLVM"); } zig_unreachable(); @@ -3240,7 +3255,7 @@ static void define_builtin_types(CodeGen *g) { { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); entry->zero_bits = true; // only allowed at compile time - buf_init_from_str(&entry->name, "@OS"); + buf_init_from_str(&entry->name, "Os"); uint32_t field_count = target_os_count(); entry->data.enumeration.src_field_count = field_count; entry->data.enumeration.fields = allocate(field_count); @@ -3249,6 +3264,7 @@ static void define_builtin_types(CodeGen *g) { ZigLLVM_OSType os_type = get_target_os(i); type_enum_field->name = buf_create_from_str(get_target_os_name(os_type)); type_enum_field->value = i; + type_enum_field->type_entry = g->builtin_types.entry_void; if (os_type == g->zig_target.os) { g->target_os_index = i; @@ -3260,12 +3276,13 @@ static void define_builtin_types(CodeGen *g) { entry->data.enumeration.tag_type = tag_type_entry; g->builtin_types.entry_os_enum = entry; + g->primitive_type_table.put(&entry->name, entry); } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); entry->zero_bits = true; // only allowed at compile time - buf_init_from_str(&entry->name, "@Arch"); + buf_init_from_str(&entry->name, "Arch"); uint32_t field_count = target_arch_count(); entry->data.enumeration.src_field_count = field_count; entry->data.enumeration.fields = allocate(field_count); @@ -3278,6 +3295,7 @@ static void define_builtin_types(CodeGen *g) { buf_resize(type_enum_field->name, strlen(buf_ptr(type_enum_field->name))); type_enum_field->value = i; + type_enum_field->type_entry = g->builtin_types.entry_void; if (arch_type->arch == g->zig_target.arch.arch && arch_type->sub_arch == g->zig_target.arch.sub_arch) @@ -3291,12 +3309,13 @@ static void define_builtin_types(CodeGen *g) { entry->data.enumeration.tag_type = tag_type_entry; g->builtin_types.entry_arch_enum = entry; + g->primitive_type_table.put(&entry->name, entry); } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); entry->zero_bits = true; // only allowed at compile time - buf_init_from_str(&entry->name, "@Environ"); + buf_init_from_str(&entry->name, "Environ"); uint32_t field_count = target_environ_count(); entry->data.enumeration.src_field_count = field_count; entry->data.enumeration.fields = allocate(field_count); @@ -3317,12 +3336,13 @@ static void define_builtin_types(CodeGen *g) { entry->data.enumeration.tag_type = tag_type_entry; g->builtin_types.entry_environ_enum = entry; + g->primitive_type_table.put(&entry->name, entry); } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); entry->zero_bits = true; // only allowed at compile time - buf_init_from_str(&entry->name, "@ObjectFormat"); + buf_init_from_str(&entry->name, "ObjectFormat"); uint32_t field_count = target_oformat_count(); entry->data.enumeration.src_field_count = field_count; entry->data.enumeration.fields = allocate(field_count); @@ -3343,6 +3363,7 @@ static void define_builtin_types(CodeGen *g) { entry->data.enumeration.tag_type = tag_type_entry; g->builtin_types.entry_oformat_enum = entry; + g->primitive_type_table.put(&entry->name, entry); } { diff --git a/src/ir.cpp b/src/ir.cpp index 8b3ef36bd8..4589af22db 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5690,8 +5690,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc var_type = decl_var_instruction->var_type->other; TypeTableEntry *proposed_type = ir_resolve_type(ira, var_type); explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type); - if (explicit_type->id == TypeTableEntryIdInvalid) - return explicit_type; + if (explicit_type->id == TypeTableEntryIdInvalid) { + var->type = ira->codegen->builtin_types.entry_invalid; + return var->type; + } } AstNode *source_node = decl_var_instruction->base.source_node; @@ -7596,6 +7598,33 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC } } +static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) { + if (value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->invalid_instruction; + + if (value->type_entry->id != TypeTableEntryIdEnum) { + ir_add_error(ira, source_instr, + buf_sprintf("expected enum type, found '%s'", buf_ptr(&value->type_entry->name))); + return ira->codegen->invalid_instruction; + } + + if (instr_is_comptime(value)) { + ConstExprValue *val = ir_resolve_const(ira, value); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstructionConst *const_instruction = ir_create_instruction(ira->new_irb.exec, + source_instr->scope, source_instr->source_node); + const_instruction->base.type_entry = value->type_entry->data.enumeration.tag_type; + const_instruction->base.static_value.special = ConstValSpecialStatic; + const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var; + bignum_init_unsigned(&const_instruction->base.static_value.data.x_bignum, val->data.x_enum.tag); + return &const_instruction->base; + } + + zig_panic("TODO runtime enum tag instruction"); +} + static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira, IrInstructionSwitchBr *switch_br_instruction) { @@ -7651,6 +7680,12 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira, if (new_value->type_entry->id == TypeTableEntryIdInvalid) continue; + if (new_value->type_entry->id == TypeTableEntryIdEnum) { + new_value = ir_analyze_enum_tag(ira, &switch_br_instruction->base, new_value); + if (new_value->type_entry->id == TypeTableEntryIdInvalid) + continue; + } + IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, target_value->type_entry); if (casted_new_value->type_entry->id == TypeTableEntryIdInvalid) continue; @@ -7719,7 +7754,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, return tag_type; } - ir_build_enum_tag_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr); + IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, + switch_target_instruction->base.source_node, target_value_ptr); + enum_value->type_entry = target_type; + ir_build_enum_tag_from(&ira->new_irb, &switch_target_instruction->base, enum_value); return tag_type; } case TypeTableEntryIdErrorUnion: @@ -7748,10 +7786,11 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, zig_panic("TODO switch var analyze"); } -static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira, - IrInstructionEnumTag *enum_tag_instruction) -{ - zig_panic("TODO ir_analyze_instruction_enum_tag"); +static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira, IrInstructionEnumTag *enum_tag_instruction) { + IrInstruction *value = enum_tag_instruction->value->other; + IrInstruction *new_instruction = ir_analyze_enum_tag(ira, &enum_tag_instruction->base, value); + ir_link_new_instruction(new_instruction, &enum_tag_instruction->base); + return new_instruction->type_entry; } static TypeTableEntry *ir_analyze_instruction_static_eval(IrAnalyze *ira, diff --git a/std/bootstrap.zig b/std/bootstrap.zig index adb263ede6..1792605859 100644 --- a/std/bootstrap.zig +++ b/std/bootstrap.zig @@ -5,7 +5,7 @@ const linux = @import("linux.zig"); const cstr = @import("cstr.zig"); const want_start_symbol = switch(@compileVar("os")) { - linux => true, + Os.linux => true, else => false, }; const want_main_symbol = !want_start_symbol; @@ -17,11 +17,11 @@ export nakedcc fn _start() -> unreachable { @setFnVisible(this, want_start_symbol); switch (@compileVar("arch")) { - x86_64 => { + Arch.x86_64 => { argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> usize)); argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8)); }, - i386 => { + Arch.i386 => { argc = asm("mov (%%esp), %[argc]": [argc] "=r" (-> usize)); argv = asm("lea 0x4(%%esp), %[argv]": [argv] "=r" (-> &&u8)); }, @@ -31,7 +31,7 @@ export nakedcc fn _start() -> unreachable { } fn callMain() -> %void { - var args: [argc][]u8 = undefined; + const args = @alloca([]u8, argc); for (args) |arg, i| { const ptr = argv[i]; args[i] = ptr[0...cstr.len(ptr)]; diff --git a/std/io.zig b/std/io.zig index be8702f44a..92de108661 100644 --- a/std/io.zig +++ b/std/io.zig @@ -34,31 +34,31 @@ pub var stderr = OutStream { /// The function received invalid input at runtime. An Invalid error means a /// bug in the program that called the function. -pub error Invalid; +error Invalid; /// When an Unexpected error occurs, code that emitted the error likely needs /// a patch to recognize the unexpected case so that it can handle it and emit /// a more specific error. -pub error Unexpected; +error Unexpected; -pub error DiskQuota; -pub error FileTooBig; -pub error Io; -pub error NoSpaceLeft; -pub error BadPerm; -pub error PipeFail; -pub error BadFd; -pub error IsDir; -pub error NotDir; -pub error SymLinkLoop; -pub error ProcessFdQuotaExceeded; -pub error SystemFdQuotaExceeded; -pub error NameTooLong; -pub error NoDevice; -pub error PathNotFound; -pub error NoMem; -pub error Unseekable; -pub error Eof; +error DiskQuota; +error FileTooBig; +error Io; +error NoSpaceLeft; +error BadPerm; +error PipeFail; +error BadFd; +error IsDir; +error NotDir; +error SymLinkLoop; +error ProcessFdQuotaExceeded; +error SystemFdQuotaExceeded; +error NameTooLong; +error NoDevice; +error PathNotFound; +error NoMem; +error Unseekable; +error Eof; const buffer_size = 4 * 1024; const max_u64_base10_digits = 20; @@ -374,7 +374,7 @@ pub fn parseUnsigned(inline T: type, buf: []u8, radix: u8) -> %T { return x; } -pub error InvalidChar; +error InvalidChar; fn charToDigit(c: u8, radix: u8) -> %u8 { const value = if ('0' <= c && c <= '9') { c - '0'