authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-17 17:48:07-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-17 17:48:07-05:00
logc64f9991d561ff9a8e3c4575e8149404784497d3
treecd452b9cef98810f74414f5c36eab8c21dd0d2c5
parent12fcbecbf8a1c8496354b909e0de2a69600115a9

IR: fix switching on enum


4 files changed, 99 insertions(+), 39 deletions(-)

src/codegen.cpp+27-6
...@@ -1420,12 +1420,12 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa...@@ -1420,12 +1420,12 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
1420static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable,1420static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable,
1421 IrInstructionEnumFieldPtr *instruction)1421 IrInstructionEnumFieldPtr *instruction)
1422{1422{
1423 LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr);
1424 TypeEnumField *field = instruction->field;1423 TypeEnumField *field = instruction->field;
14251424
1426 if (!type_has_bits(field->type_entry))1425 if (!type_has_bits(field->type_entry))
1427 return nullptr;1426 return nullptr;
14281427
1428 LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr);
1429 LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);1429 LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
1430 LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_gen_union_index, "");1430 LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_gen_union_index, "");
1431 LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");1431 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...@@ -2140,6 +2140,20 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
2140 return instruction->tmp_ptr;2140 return instruction->tmp_ptr;
2141}2141}
21422142
2143static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrInstructionEnumTag *instruction) {
2144 TypeTableEntry *enum_type = instruction->value->type_entry;
2145 TypeTableEntry *tag_type = enum_type->data.enumeration.tag_type;
2146 if (!type_has_bits(tag_type))
2147 return nullptr;
2148
2149 LLVMValueRef enum_val = ir_llvm_value(g, instruction->value);
2150 if (enum_type->data.enumeration.gen_field_count == 0)
2151 return enum_val;
2152
2153 LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_gen_tag_index, "");
2154 return get_handle_value(g, tag_field_ptr, tag_type);
2155}
2156
2143static void set_debug_location(CodeGen *g, IrInstruction *instruction) {2157static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
2144 AstNode *source_node = instruction->source_node;2158 AstNode *source_node = instruction->source_node;
2145 Scope *scope = instruction->scope;2159 Scope *scope = instruction->scope;
...@@ -2271,10 +2285,11 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -2271,10 +2285,11 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
2271 return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);2285 return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);
2272 case IrInstructionIdErrWrapPayload:2286 case IrInstructionIdErrWrapPayload:
2273 return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction);2287 return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction);
2288 case IrInstructionIdEnumTag:
2289 return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction);
2274 case IrInstructionIdSwitchVar:2290 case IrInstructionIdSwitchVar:
2275 case IrInstructionIdContainerInitList:2291 case IrInstructionIdContainerInitList:
2276 case IrInstructionIdStructInit:2292 case IrInstructionIdStructInit:
2277 case IrInstructionIdEnumTag:
2278 zig_panic("TODO render more IR instructions to LLVM");2293 zig_panic("TODO render more IR instructions to LLVM");
2279 }2294 }
2280 zig_unreachable();2295 zig_unreachable();
...@@ -3240,7 +3255,7 @@ static void define_builtin_types(CodeGen *g) {...@@ -3240,7 +3255,7 @@ static void define_builtin_types(CodeGen *g) {
3240 {3255 {
3241 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);3256 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
3242 entry->zero_bits = true; // only allowed at compile time3257 entry->zero_bits = true; // only allowed at compile time
3243 buf_init_from_str(&entry->name, "@OS");3258 buf_init_from_str(&entry->name, "Os");
3244 uint32_t field_count = target_os_count();3259 uint32_t field_count = target_os_count();
3245 entry->data.enumeration.src_field_count = field_count;3260 entry->data.enumeration.src_field_count = field_count;
3246 entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);3261 entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
...@@ -3249,6 +3264,7 @@ static void define_builtin_types(CodeGen *g) {...@@ -3249,6 +3264,7 @@ static void define_builtin_types(CodeGen *g) {
3249 ZigLLVM_OSType os_type = get_target_os(i);3264 ZigLLVM_OSType os_type = get_target_os(i);
3250 type_enum_field->name = buf_create_from_str(get_target_os_name(os_type));3265 type_enum_field->name = buf_create_from_str(get_target_os_name(os_type));
3251 type_enum_field->value = i;3266 type_enum_field->value = i;
3267 type_enum_field->type_entry = g->builtin_types.entry_void;
32523268
3253 if (os_type == g->zig_target.os) {3269 if (os_type == g->zig_target.os) {
3254 g->target_os_index = i;3270 g->target_os_index = i;
...@@ -3260,12 +3276,13 @@ static void define_builtin_types(CodeGen *g) {...@@ -3260,12 +3276,13 @@ static void define_builtin_types(CodeGen *g) {
3260 entry->data.enumeration.tag_type = tag_type_entry;3276 entry->data.enumeration.tag_type = tag_type_entry;
32613277
3262 g->builtin_types.entry_os_enum = entry;3278 g->builtin_types.entry_os_enum = entry;
3279 g->primitive_type_table.put(&entry->name, entry);
3263 }3280 }
32643281
3265 {3282 {
3266 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);3283 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
3267 entry->zero_bits = true; // only allowed at compile time3284 entry->zero_bits = true; // only allowed at compile time
3268 buf_init_from_str(&entry->name, "@Arch");3285 buf_init_from_str(&entry->name, "Arch");
3269 uint32_t field_count = target_arch_count();3286 uint32_t field_count = target_arch_count();
3270 entry->data.enumeration.src_field_count = field_count;3287 entry->data.enumeration.src_field_count = field_count;
3271 entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);3288 entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
...@@ -3278,6 +3295,7 @@ static void define_builtin_types(CodeGen *g) {...@@ -3278,6 +3295,7 @@ static void define_builtin_types(CodeGen *g) {
3278 buf_resize(type_enum_field->name, strlen(buf_ptr(type_enum_field->name)));3295 buf_resize(type_enum_field->name, strlen(buf_ptr(type_enum_field->name)));
32793296
3280 type_enum_field->value = i;3297 type_enum_field->value = i;
3298 type_enum_field->type_entry = g->builtin_types.entry_void;
32813299
3282 if (arch_type->arch == g->zig_target.arch.arch &&3300 if (arch_type->arch == g->zig_target.arch.arch &&
3283 arch_type->sub_arch == g->zig_target.arch.sub_arch)3301 arch_type->sub_arch == g->zig_target.arch.sub_arch)
...@@ -3291,12 +3309,13 @@ static void define_builtin_types(CodeGen *g) {...@@ -3291,12 +3309,13 @@ static void define_builtin_types(CodeGen *g) {
3291 entry->data.enumeration.tag_type = tag_type_entry;3309 entry->data.enumeration.tag_type = tag_type_entry;
32923310
3293 g->builtin_types.entry_arch_enum = entry;3311 g->builtin_types.entry_arch_enum = entry;
3312 g->primitive_type_table.put(&entry->name, entry);
3294 }3313 }
32953314
3296 {3315 {
3297 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);3316 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
3298 entry->zero_bits = true; // only allowed at compile time3317 entry->zero_bits = true; // only allowed at compile time
3299 buf_init_from_str(&entry->name, "@Environ");3318 buf_init_from_str(&entry->name, "Environ");
3300 uint32_t field_count = target_environ_count();3319 uint32_t field_count = target_environ_count();
3301 entry->data.enumeration.src_field_count = field_count;3320 entry->data.enumeration.src_field_count = field_count;
3302 entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);3321 entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
...@@ -3317,12 +3336,13 @@ static void define_builtin_types(CodeGen *g) {...@@ -3317,12 +3336,13 @@ static void define_builtin_types(CodeGen *g) {
3317 entry->data.enumeration.tag_type = tag_type_entry;3336 entry->data.enumeration.tag_type = tag_type_entry;
33183337
3319 g->builtin_types.entry_environ_enum = entry;3338 g->builtin_types.entry_environ_enum = entry;
3339 g->primitive_type_table.put(&entry->name, entry);
3320 }3340 }
33213341
3322 {3342 {
3323 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);3343 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
3324 entry->zero_bits = true; // only allowed at compile time3344 entry->zero_bits = true; // only allowed at compile time
3325 buf_init_from_str(&entry->name, "@ObjectFormat");3345 buf_init_from_str(&entry->name, "ObjectFormat");
3326 uint32_t field_count = target_oformat_count();3346 uint32_t field_count = target_oformat_count();
3327 entry->data.enumeration.src_field_count = field_count;3347 entry->data.enumeration.src_field_count = field_count;
3328 entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);3348 entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
...@@ -3343,6 +3363,7 @@ static void define_builtin_types(CodeGen *g) {...@@ -3343,6 +3363,7 @@ static void define_builtin_types(CodeGen *g) {
3343 entry->data.enumeration.tag_type = tag_type_entry;3363 entry->data.enumeration.tag_type = tag_type_entry;
33443364
3345 g->builtin_types.entry_oformat_enum = entry;3365 g->builtin_types.entry_oformat_enum = entry;
3366 g->primitive_type_table.put(&entry->name, entry);
3346 }3367 }
33473368
3348 {3369 {
src/ir.cpp+46-7
...@@ -5690,8 +5690,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -5690,8 +5690,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
5690 var_type = decl_var_instruction->var_type->other;5690 var_type = decl_var_instruction->var_type->other;
5691 TypeTableEntry *proposed_type = ir_resolve_type(ira, var_type);5691 TypeTableEntry *proposed_type = ir_resolve_type(ira, var_type);
5692 explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type);5692 explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type);
5693 if (explicit_type->id == TypeTableEntryIdInvalid)5693 if (explicit_type->id == TypeTableEntryIdInvalid) {
5694 return explicit_type;5694 var->type = ira->codegen->builtin_types.entry_invalid;
5695 return var->type;
5696 }
5695 }5697 }
56965698
5697 AstNode *source_node = decl_var_instruction->base.source_node;5699 AstNode *source_node = decl_var_instruction->base.source_node;
...@@ -7596,6 +7598,33 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC...@@ -7596,6 +7598,33 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC
7596 }7598 }
7597}7599}
75987600
7601static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) {
7602 if (value->type_entry->id == TypeTableEntryIdInvalid)
7603 return ira->codegen->invalid_instruction;
7604
7605 if (value->type_entry->id != TypeTableEntryIdEnum) {
7606 ir_add_error(ira, source_instr,
7607 buf_sprintf("expected enum type, found '%s'", buf_ptr(&value->type_entry->name)));
7608 return ira->codegen->invalid_instruction;
7609 }
7610
7611 if (instr_is_comptime(value)) {
7612 ConstExprValue *val = ir_resolve_const(ira, value);
7613 if (!val)
7614 return ira->codegen->invalid_instruction;
7615
7616 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
7617 source_instr->scope, source_instr->source_node);
7618 const_instruction->base.type_entry = value->type_entry->data.enumeration.tag_type;
7619 const_instruction->base.static_value.special = ConstValSpecialStatic;
7620 const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
7621 bignum_init_unsigned(&const_instruction->base.static_value.data.x_bignum, val->data.x_enum.tag);
7622 return &const_instruction->base;
7623 }
7624
7625 zig_panic("TODO runtime enum tag instruction");
7626}
7627
7599static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,7628static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
7600 IrInstructionSwitchBr *switch_br_instruction)7629 IrInstructionSwitchBr *switch_br_instruction)
7601{7630{
...@@ -7651,6 +7680,12 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,...@@ -7651,6 +7680,12 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
7651 if (new_value->type_entry->id == TypeTableEntryIdInvalid)7680 if (new_value->type_entry->id == TypeTableEntryIdInvalid)
7652 continue;7681 continue;
76537682
7683 if (new_value->type_entry->id == TypeTableEntryIdEnum) {
7684 new_value = ir_analyze_enum_tag(ira, &switch_br_instruction->base, new_value);
7685 if (new_value->type_entry->id == TypeTableEntryIdInvalid)
7686 continue;
7687 }
7688
7654 IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, target_value->type_entry);7689 IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, target_value->type_entry);
7655 if (casted_new_value->type_entry->id == TypeTableEntryIdInvalid)7690 if (casted_new_value->type_entry->id == TypeTableEntryIdInvalid)
7656 continue;7691 continue;
...@@ -7719,7 +7754,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -7719,7 +7754,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
7719 return tag_type;7754 return tag_type;
7720 }7755 }
77217756
7722 ir_build_enum_tag_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr);7757 IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
7758 switch_target_instruction->base.source_node, target_value_ptr);
7759 enum_value->type_entry = target_type;
7760 ir_build_enum_tag_from(&ira->new_irb, &switch_target_instruction->base, enum_value);
7723 return tag_type;7761 return tag_type;
7724 }7762 }
7725 case TypeTableEntryIdErrorUnion:7763 case TypeTableEntryIdErrorUnion:
...@@ -7748,10 +7786,11 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira,...@@ -7748,10 +7786,11 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira,
7748 zig_panic("TODO switch var analyze");7786 zig_panic("TODO switch var analyze");
7749}7787}
77507788
7751static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira,7789static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira, IrInstructionEnumTag *enum_tag_instruction) {
7752 IrInstructionEnumTag *enum_tag_instruction)7790 IrInstruction *value = enum_tag_instruction->value->other;
7753{7791 IrInstruction *new_instruction = ir_analyze_enum_tag(ira, &enum_tag_instruction->base, value);
7754 zig_panic("TODO ir_analyze_instruction_enum_tag");7792 ir_link_new_instruction(new_instruction, &enum_tag_instruction->base);
7793 return new_instruction->type_entry;
7755}7794}
77567795
7757static TypeTableEntry *ir_analyze_instruction_static_eval(IrAnalyze *ira,7796static TypeTableEntry *ir_analyze_instruction_static_eval(IrAnalyze *ira,
std/bootstrap.zig+4-4
...@@ -5,7 +5,7 @@ const linux = @import("linux.zig");...@@ -5,7 +5,7 @@ const linux = @import("linux.zig");
5const cstr = @import("cstr.zig");5const cstr = @import("cstr.zig");
66
7const want_start_symbol = switch(@compileVar("os")) {7const want_start_symbol = switch(@compileVar("os")) {
8 linux => true,8 Os.linux => true,
9 else => false,9 else => false,
10};10};
11const want_main_symbol = !want_start_symbol;11const want_main_symbol = !want_start_symbol;
...@@ -17,11 +17,11 @@ export nakedcc fn _start() -> unreachable {...@@ -17,11 +17,11 @@ export nakedcc fn _start() -> unreachable {
17 @setFnVisible(this, want_start_symbol);17 @setFnVisible(this, want_start_symbol);
1818
19 switch (@compileVar("arch")) {19 switch (@compileVar("arch")) {
20 x86_64 => {20 Arch.x86_64 => {
21 argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> usize));21 argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> usize));
22 argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));22 argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
23 },23 },
24 i386 => {24 Arch.i386 => {
25 argc = asm("mov (%%esp), %[argc]": [argc] "=r" (-> usize));25 argc = asm("mov (%%esp), %[argc]": [argc] "=r" (-> usize));
26 argv = asm("lea 0x4(%%esp), %[argv]": [argv] "=r" (-> &&u8));26 argv = asm("lea 0x4(%%esp), %[argv]": [argv] "=r" (-> &&u8));
27 },27 },
...@@ -31,7 +31,7 @@ export nakedcc fn _start() -> unreachable {...@@ -31,7 +31,7 @@ export nakedcc fn _start() -> unreachable {
31}31}
3232
33fn callMain() -> %void {33fn callMain() -> %void {
34 var args: [argc][]u8 = undefined;34 const args = @alloca([]u8, argc);
35 for (args) |arg, i| {35 for (args) |arg, i| {
36 const ptr = argv[i];36 const ptr = argv[i];
37 args[i] = ptr[0...cstr.len(ptr)];37 args[i] = ptr[0...cstr.len(ptr)];
std/io.zig+22-22
...@@ -34,31 +34,31 @@ pub var stderr = OutStream {...@@ -34,31 +34,31 @@ pub var stderr = OutStream {
3434
35/// The function received invalid input at runtime. An Invalid error means a35/// The function received invalid input at runtime. An Invalid error means a
36/// bug in the program that called the function.36/// bug in the program that called the function.
37pub error Invalid;37error Invalid;
3838
39/// When an Unexpected error occurs, code that emitted the error likely needs39/// When an Unexpected error occurs, code that emitted the error likely needs
40/// a patch to recognize the unexpected case so that it can handle it and emit40/// a patch to recognize the unexpected case so that it can handle it and emit
41/// a more specific error.41/// a more specific error.
42pub error Unexpected;42error Unexpected;
4343
44pub error DiskQuota;44error DiskQuota;
45pub error FileTooBig;45error FileTooBig;
46pub error Io;46error Io;
47pub error NoSpaceLeft;47error NoSpaceLeft;
48pub error BadPerm;48error BadPerm;
49pub error PipeFail;49error PipeFail;
50pub error BadFd;50error BadFd;
51pub error IsDir;51error IsDir;
52pub error NotDir;52error NotDir;
53pub error SymLinkLoop;53error SymLinkLoop;
54pub error ProcessFdQuotaExceeded;54error ProcessFdQuotaExceeded;
55pub error SystemFdQuotaExceeded;55error SystemFdQuotaExceeded;
56pub error NameTooLong;56error NameTooLong;
57pub error NoDevice;57error NoDevice;
58pub error PathNotFound;58error PathNotFound;
59pub error NoMem;59error NoMem;
60pub error Unseekable;60error Unseekable;
61pub error Eof;61error Eof;
6262
63const buffer_size = 4 * 1024;63const buffer_size = 4 * 1024;
64const max_u64_base10_digits = 20;64const max_u64_base10_digits = 20;
...@@ -374,7 +374,7 @@ pub fn parseUnsigned(inline T: type, buf: []u8, radix: u8) -> %T {...@@ -374,7 +374,7 @@ pub fn parseUnsigned(inline T: type, buf: []u8, radix: u8) -> %T {
374 return x;374 return x;
375}375}
376376
377pub error InvalidChar;377error InvalidChar;
378fn charToDigit(c: u8, radix: u8) -> %u8 {378fn charToDigit(c: u8, radix: u8) -> %u8 {
379 const value = if ('0' <= c && c <= '9') {379 const value = if ('0' <= c && c <= '9') {
380 c - '0'380 c - '0'