| ... | ... | @@ -875,6 +875,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { |
| 875 | 875 | return buf_create_from_str("incorrect alignment"); |
| 876 | 876 | case PanicMsgIdBadUnionField: |
| 877 | 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 | 881 | zig_unreachable(); |
| 880 | 882 | } |
| ... | ... | @@ -3516,34 +3518,112 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI |
| 3516 | 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 | 3616 | static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable, |
| 3520 | 3617 | IrInstructionTagName *instruction) |
| 3521 | 3618 | { |
| 3522 | 3619 | TypeTableEntry *enum_type = instruction->target->value.type; |
| 3523 | 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; |
| 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 | | } |
| 3622 | LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type); |
| 3540 | 3623 | |
| 3541 | | LLVMValueRef indices[] = { |
| 3542 | | LLVMConstNull(g->builtin_types.entry_usize->type_ref), |
| 3543 | | gen_widen_or_shorten(g, false, tag_int_type, |
| 3544 | | g->builtin_types.entry_usize, enum_tag_value), |
| 3545 | | }; |
| 3546 | | return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, ""); |
| 3624 | LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); |
| 3625 | return ZigLLVMBuildCall(g->builder, enum_name_function, &enum_tag_value, 1, |
| 3626 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); |
| 3547 | 3627 | } |
| 3548 | 3628 | |
| 3549 | 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 | 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 | 5554 | static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) { |
| 5524 | 5555 | IrExecutable *executable = &fn->analyzed_executable; |
| 5525 | 5556 | assert(executable->basic_block_list.length > 0); |
| ... | ... | @@ -5616,7 +5647,6 @@ static void do_code_gen(CodeGen *g) { |
| 5616 | 5647 | } |
| 5617 | 5648 | |
| 5618 | 5649 | generate_error_name_table(g); |
| 5619 | | generate_enum_name_tables(g); |
| 5620 | 5650 | |
| 5621 | 5651 | // Generate module level variables |
| 5622 | 5652 | for (size_t i = 0; i < g->global_vars.length; i += 1) { |