| ... | @@ -875,6 +875,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { | ... | @@ -875,6 +875,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { |
| 875 | return buf_create_from_str("incorrect alignment"); | 875 | return buf_create_from_str("incorrect alignment"); |
| 876 | case PanicMsgIdBadUnionField: | 876 | case PanicMsgIdBadUnionField: |
| 877 | return buf_create_from_str("access of inactive union field"); | 877 | return buf_create_from_str("access of inactive union field"); |
| | 878 | case PanicMsgIdBadEnumValue: |
| | 879 | return buf_create_from_str("invalid enum value"); |
| 878 | } | 880 | } |
| 879 | zig_unreachable(); | 881 | zig_unreachable(); |
| 880 | } | 882 | } |
| ... | @@ -3516,34 +3518,112 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI | ... | @@ -3516,34 +3518,112 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI |
| 3516 | return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, ""); | 3518 | return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, ""); |
| 3517 | } | 3519 | } |
| 3518 | | 3520 | |
| | 3521 | static LLVMValueRef get_enum_tag_name_function(CodeGen *g, TypeTableEntry *enum_type) { |
| | 3522 | assert(enum_type->id == TypeTableEntryIdEnum); |
| | 3523 | if (enum_type->data.enumeration.name_function) |
| | 3524 | return enum_type->data.enumeration.name_function; |
| | 3525 | |
| | 3526 | TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false, |
| | 3527 | PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0); |
| | 3528 | TypeTableEntry *u8_slice_type = get_slice_type(g, u8_ptr_type); |
| | 3529 | TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type; |
| | 3530 | |
| | 3531 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(u8_slice_type->type_ref, 0), |
| | 3532 | &tag_int_type->type_ref, 1, false); |
| | 3533 | |
| | 3534 | Buf *fn_name = get_mangled_name(g, buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)), false); |
| | 3535 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); |
| | 3536 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| | 3537 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); |
| | 3538 | addLLVMFnAttr(fn_val, "nounwind"); |
| | 3539 | add_uwtable_attr(g, fn_val); |
| | 3540 | if (g->build_mode == BuildModeDebug) { |
| | 3541 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); |
| | 3542 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr); |
| | 3543 | } |
| | 3544 | |
| | 3545 | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); |
| | 3546 | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); |
| | 3547 | FnTableEntry *prev_cur_fn = g->cur_fn; |
| | 3548 | LLVMValueRef prev_cur_fn_val = g->cur_fn_val; |
| | 3549 | |
| | 3550 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); |
| | 3551 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| | 3552 | ZigLLVMClearCurrentDebugLocation(g->builder); |
| | 3553 | g->cur_fn = nullptr; |
| | 3554 | g->cur_fn_val = fn_val; |
| | 3555 | |
| | 3556 | size_t field_count = enum_type->data.enumeration.src_field_count; |
| | 3557 | LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue"); |
| | 3558 | LLVMValueRef tag_int_value = LLVMGetParam(fn_val, 0); |
| | 3559 | LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count); |
| | 3560 | |
| | 3561 | |
| | 3562 | TypeTableEntry *usize = g->builtin_types.entry_usize; |
| | 3563 | LLVMValueRef array_ptr_indices[] = { |
| | 3564 | LLVMConstNull(usize->type_ref), |
| | 3565 | LLVMConstNull(usize->type_ref), |
| | 3566 | }; |
| | 3567 | |
| | 3568 | for (size_t field_i = 0; field_i < field_count; field_i += 1) { |
| | 3569 | Buf *name = enum_type->data.enumeration.fields[field_i].name; |
| | 3570 | LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true); |
| | 3571 | LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); |
| | 3572 | LLVMSetInitializer(str_global, str_init); |
| | 3573 | LLVMSetLinkage(str_global, LLVMPrivateLinkage); |
| | 3574 | LLVMSetGlobalConstant(str_global, true); |
| | 3575 | LLVMSetUnnamedAddr(str_global, true); |
| | 3576 | LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init))); |
| | 3577 | |
| | 3578 | LLVMValueRef fields[] = { |
| | 3579 | LLVMConstGEP(str_global, array_ptr_indices, 2), |
| | 3580 | LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false), |
| | 3581 | }; |
| | 3582 | LLVMValueRef slice_init_value = LLVMConstNamedStruct(u8_slice_type->type_ref, fields, 2); |
| | 3583 | |
| | 3584 | LLVMValueRef slice_global = LLVMAddGlobal(g->module, LLVMTypeOf(slice_init_value), ""); |
| | 3585 | LLVMSetInitializer(slice_global, slice_init_value); |
| | 3586 | LLVMSetLinkage(slice_global, LLVMPrivateLinkage); |
| | 3587 | LLVMSetGlobalConstant(slice_global, true); |
| | 3588 | LLVMSetUnnamedAddr(slice_global, true); |
| | 3589 | LLVMSetAlignment(slice_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(slice_init_value))); |
| | 3590 | |
| | 3591 | LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "Name"); |
| | 3592 | LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref, |
| | 3593 | &enum_type->data.enumeration.fields[field_i].value); |
| | 3594 | LLVMAddCase(switch_instr, this_tag_int_value, return_block); |
| | 3595 | |
| | 3596 | LLVMPositionBuilderAtEnd(g->builder, return_block); |
| | 3597 | LLVMBuildRet(g->builder, slice_global); |
| | 3598 | } |
| | 3599 | |
| | 3600 | LLVMPositionBuilderAtEnd(g->builder, bad_value_block); |
| | 3601 | if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) { |
| | 3602 | gen_safety_crash(g, PanicMsgIdBadEnumValue); |
| | 3603 | } else { |
| | 3604 | LLVMBuildUnreachable(g->builder); |
| | 3605 | } |
| | 3606 | |
| | 3607 | g->cur_fn = prev_cur_fn; |
| | 3608 | g->cur_fn_val = prev_cur_fn_val; |
| | 3609 | LLVMPositionBuilderAtEnd(g->builder, prev_block); |
| | 3610 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); |
| | 3611 | |
| | 3612 | enum_type->data.enumeration.name_function = fn_val; |
| | 3613 | return fn_val; |
| | 3614 | } |
| | 3615 | |
| 3519 | static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable, | 3616 | static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable, |
| 3520 | IrInstructionTagName *instruction) | 3617 | IrInstructionTagName *instruction) |
| 3521 | { | 3618 | { |
| 3522 | TypeTableEntry *enum_type = instruction->target->value.type; | 3619 | TypeTableEntry *enum_type = instruction->target->value.type; |
| 3523 | assert(enum_type->id == TypeTableEntryIdEnum); | 3620 | assert(enum_type->id == TypeTableEntryIdEnum); |
| 3524 | assert(enum_type->data.enumeration.generate_name_table); | | |
| 3525 | | 3621 | |
| 3526 | TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type; | 3622 | LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type); |
| 3527 | LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); | | |
| 3528 | if (ir_want_runtime_safety(g, &instruction->base)) { | | |
| 3529 | size_t field_count = enum_type->data.enumeration.src_field_count; | | |
| 3530 | | | |
| 3531 | // if the field_count can't fit in the bits of the enum_type, then it can't possibly | | |
| 3532 | // be the wrong value | | |
| 3533 | BigInt field_bi; | | |
| 3534 | bigint_init_unsigned(&field_bi, field_count); | | |
| 3535 | if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) { | | |
| 3536 | LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false); | | |
| 3537 | add_bounds_check(g, enum_tag_value, LLVMIntEQ, nullptr, LLVMIntULT, end_val); | | |
| 3538 | } | | |
| 3539 | } | | |
| 3540 | | 3623 | |
| 3541 | LLVMValueRef indices[] = { | 3624 | LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); |
| 3542 | LLVMConstNull(g->builtin_types.entry_usize->type_ref), | 3625 | return ZigLLVMBuildCall(g->builder, enum_name_function, &enum_tag_value, 1, |
| 3543 | gen_widen_or_shorten(g, false, tag_int_type, | 3626 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); |
| 3544 | g->builtin_types.entry_usize, enum_tag_value), | | |
| 3545 | }; | | |
| 3546 | return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, ""); | | |
| 3547 | } | 3627 | } |
| 3548 | | 3628 | |
| 3549 | static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable, | 3629 | static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable, |
| ... | @@ -5471,55 +5551,6 @@ static void generate_error_name_table(CodeGen *g) { | ... | @@ -5471,55 +5551,6 @@ static void generate_error_name_table(CodeGen *g) { |
| 5471 | LLVMSetAlignment(g->err_name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(err_name_table_init))); | 5551 | LLVMSetAlignment(g->err_name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(err_name_table_init))); |
| 5472 | } | 5552 | } |
| 5473 | | 5553 | |
| 5474 | static void generate_enum_name_tables(CodeGen *g) { | | |
| 5475 | TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, | | |
| 5476 | PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0); | | |
| 5477 | TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type); | | |
| 5478 | | | |
| 5479 | TypeTableEntry *usize = g->builtin_types.entry_usize; | | |
| 5480 | LLVMValueRef array_ptr_indices[] = { | | |
| 5481 | LLVMConstNull(usize->type_ref), | | |
| 5482 | LLVMConstNull(usize->type_ref), | | |
| 5483 | }; | | |
| 5484 | | | |
| 5485 | | | |
| 5486 | for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) { | | |
| 5487 | TypeTableEntry *enum_type = g->name_table_enums.at(enum_i); | | |
| 5488 | assert(enum_type->id == TypeTableEntryIdEnum); | | |
| 5489 | | | |
| 5490 | size_t field_count = enum_type->data.enumeration.src_field_count; | | |
| 5491 | LLVMValueRef *values = allocate<LLVMValueRef>(field_count); | | |
| 5492 | for (size_t field_i = 0; field_i < field_count; field_i += 1) { | | |
| 5493 | Buf *name = enum_type->data.enumeration.fields[field_i].name; | | |
| 5494 | | | |
| 5495 | LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true); | | |
| 5496 | LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); | | |
| 5497 | LLVMSetInitializer(str_global, str_init); | | |
| 5498 | LLVMSetLinkage(str_global, LLVMPrivateLinkage); | | |
| 5499 | LLVMSetGlobalConstant(str_global, true); | | |
| 5500 | LLVMSetUnnamedAddr(str_global, true); | | |
| 5501 | LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init))); | | |
| 5502 | | | |
| 5503 | LLVMValueRef fields[] = { | | |
| 5504 | LLVMConstGEP(str_global, array_ptr_indices, 2), | | |
| 5505 | LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false), | | |
| 5506 | }; | | |
| 5507 | values[field_i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2); | | |
| 5508 | } | | |
| 5509 | | | |
| 5510 | LLVMValueRef name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)field_count); | | |
| 5511 | | | |
| 5512 | Buf *table_name = get_mangled_name(g, buf_sprintf("%s_name_table", buf_ptr(&enum_type->name)), false); | | |
| 5513 | LLVMValueRef name_table = LLVMAddGlobal(g->module, LLVMTypeOf(name_table_init), buf_ptr(table_name)); | | |
| 5514 | LLVMSetInitializer(name_table, name_table_init); | | |
| 5515 | LLVMSetLinkage(name_table, LLVMPrivateLinkage); | | |
| 5516 | LLVMSetGlobalConstant(name_table, true); | | |
| 5517 | LLVMSetUnnamedAddr(name_table, true); | | |
| 5518 | LLVMSetAlignment(name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(name_table_init))); | | |
| 5519 | enum_type->data.enumeration.name_table = name_table; | | |
| 5520 | } | | |
| 5521 | } | | |
| 5522 | | | |
| 5523 | static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) { | 5554 | static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) { |
| 5524 | IrExecutable *executable = &fn->analyzed_executable; | 5555 | IrExecutable *executable = &fn->analyzed_executable; |
| 5525 | assert(executable->basic_block_list.length > 0); | 5556 | assert(executable->basic_block_list.length > 0); |
| ... | @@ -5616,7 +5647,6 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5616,7 +5647,6 @@ static void do_code_gen(CodeGen *g) { |
| 5616 | } | 5647 | } |
| 5617 | | 5648 | |
| 5618 | generate_error_name_table(g); | 5649 | generate_error_name_table(g); |
| 5619 | generate_enum_name_tables(g); | | |
| 5620 | | 5650 | |
| 5621 | // Generate module level variables | 5651 | // Generate module level variables |
| 5622 | for (size_t i = 0; i < g->global_vars.length; i += 1) { | 5652 | for (size_t i = 0; i < g->global_vars.length; i += 1) { |