@@ -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 ) {
0 commit comments